释放动态数组的问题,可能有点难。 (0分)

  • 主题发起人 主题发起人 ycsx
  • 开始时间 开始时间
Y

ycsx

Unregistered / Unconfirmed
GUEST, unregistred user!
请看这样一段代码:
TSubArray = record
Item1 : string;
Item2 : string;
end;
TMyArray = record
Items : Array of TSubArray;
end;
....

var
myArray : Array of TMyArray;
begin
SetLength(myArray,2);
SetLength(myArray[0].SubArray,2);
SetLength(myArray[1].SubArray,3);
myArray[0].SubArray[0] := 'abc';
.....
SetLength(myArray,0);
end

问题是:有没有必要加这样的代码:
SetLength(myArray[0].SubArray,0);
SetLength(myArray[1].SubArray,0);
.....
 
要释放的是 SubArray 中的 Item1、Item2, 让他等于 '';
最好不要在记录中使用 string 类型变量。
 
没必要,String类型是自动内存维护的,但加上后自我感觉会好点。
 
除非你的array非常大,想节省内存,所以用完第一时间就释放它
否则就是多此一举。
 
ok 同意楼上的看法;
 
绝对有必要,记住,凡是用setlength动态分配的,都应该setlength(0)

xianjun: 你小子的意思是不是说,因为如果老子暴富,就不用在乎钱包是不是漏的?
 
凡是用setlength动态分配的,都应该setlength(0)
这个“凡是”是从哪得来的?
不懂就别乱说!
 
调用SetLength时,如果操作对象是动态数组,Delphi实际上会自动加上保护代码
例如
var
Data: array of Integer;
begin
SetLength(Data, 10);
end;
实际上代码会类似
var
Data: array of Integer;
begin
try
_DynArraySetLength
//SetLength(Data, 10);
finally
_DynArrayClear
// 类似 FreeMem
end;
end;
因此并不需要手工SetLength(0)来释放内存
但是如果你的数组中保存的是对象或者其他动态分配内存的数据
比如你例子中的二维数组,这时Delphi没有义务帮你释放
也就是说二维数组中第二维需要手工释放,第一维会自动维护
 
我所说的意思是:
在myArray中保存着SubArray的指针,而SubArray中又保存着Item1和Item2指针,那么仅仅
释放myArray,系统会不会自动根据SubArray的指针去找释放Item1和item2的内容,然后
再去释放subArray呢?
 
我的意思很明确了啊?二维数组中第二维,也就是你的SubArray需要自己维护
而第一维的myArray系统自动维护,原因见前面的帖子
 
因为你的Item1和Item2是String类型,String是生存期自管理类型,所以也不用手工释放
 
to flier:
看得勿忙,你下面的内容没有注意到。呵呵。
我的感觉也是应该自己手工释放。
 
to ycsx:
呵呵,讨论到这里可能你很难相信谁的是正确的吧?其实最简单的办法就是自己做实验!
可以用MemProof或Memory Sleuth来检测一下有无内存泄漏。 在我这里是没发现有内存
泄漏,所以我还是坚持我的观点。 [:)]

我的测试代码:
type
TSubArray = record
Item1 : string;
Item2 : string;
end;
TMyArray = record
Items : Array of TSubArray;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
myArray : Array of TMyArray;
begin
SetLength(myArray,2);
SetLength(myArray[0].Items,2);
SetLength(myArray[1].Items,3);
myArray[0].Items[0].Item1 := 'abc';
myArray[0].Items[1].Item1 := 'abc';
myArray[1].Items[0].Item1 := 'abc';
myArray[1].Items[1].Item1 := 'abc';
myArray[1].Items[2].Item1 := 'abc';
myArray[0].Items[0].Item2 := 'abc';
myArray[0].Items[1].Item2 := 'abc';
myArray[1].Items[0].Item2 := 'abc';
myArray[1].Items[1].Item2 := 'abc';
myArray[1].Items[2].Item2 := 'abc';
ShowMessage(myArray[1].Items[2].Item2);
//下面这三句加上与不加结果是一样的! 都没有内存泄漏问题
SetLength(myArray[0].Items,0);
SetLength(myArray[1].Items,0);
SetLength(myArray,0);
end;
 
需要释放的,不然会泄露啊。
delphi并没有类似于java的gc机制,它只会对引用进行计数,并当引用为0时释放对象,
但对于一个数组,如果数组中又包含一个指针指向另一个对象or数组,它并不会把它释放掉的。
可以做个demo试试看啊,不要在这边这样争了。
我去写code了。
 
我好像忽略了一点,对动态类型如动态数组,Delphi的确做了特殊处理
_FinalizeArray会递归释放所有层的动态数组。
_FinalizeArray实际上处理了字符串、Variant、Array, DynArray,
Record, Interface等类型的嵌套动态释放问题,但对其他诸如指针、
Object等无法处理。
因此,动态类型的嵌套定义的确可以自动处理,除非内涵指针、Object等
 
我一般只是看提问者的问题来回答,对于本题的动态数组是不用释放的

如果你的数组是Array of TObject! 那对于数组中的每一个TObject你都是要手动释放的
这其实也很好判断,因为每个TObject都是你显式创建出来的。但对数组本身你还是可以让
Delphi来帮你完成。
 
后退
顶部