大家看看这样释放内存是否干净。
var
PRECA = ^TRECA; TRECA = record
s: string;
i: Integer;
end;procedure DoSth;
var
LI: TListItem;
tmpPRECA: PRECA;
begin
New(tmpPRECA);
tmpPRECA.s := 'hi';
tmpPRECA.i := 123;
LI := ListView1.Items.Add;
LI.Caption := tmpPRECA.s;
LI.Data := tmpPRECA;
end;procedure ClearLV;
var
i: Integer;
begin
for i := 0 to ListView1.Items.Count - 1 do
begin
if ListView1.Items.Item[i].Data <> nil then
Dispose(ListView1.Items.Item[i].Data);//做法1
if ListView1.Items.Item[i].Data <> nil then
Dispose(PRECA(ListView1.Items.Item[i].Data));//做法2
end;
end;
================================================
想请教在做法1里面,用Dispose过程正常释放内存吗?
var
PRECA = ^TRECA; TRECA = record
s: string;
i: Integer;
end;procedure DoSth;
var
LI: TListItem;
tmpPRECA: PRECA;
begin
New(tmpPRECA);
tmpPRECA.s := 'hi';
tmpPRECA.i := 123;
LI := ListView1.Items.Add;
LI.Caption := tmpPRECA.s;
LI.Data := tmpPRECA;
end;procedure ClearLV;
var
i: Integer;
begin
for i := 0 to ListView1.Items.Count - 1 do
begin
if ListView1.Items.Item[i].Data <> nil then
Dispose(ListView1.Items.Item[i].Data);//做法1
if ListView1.Items.Item[i].Data <> nil then
Dispose(PRECA(ListView1.Items.Item[i].Data));//做法2
end;
end;
================================================
想请教在做法1里面,用Dispose过程正常释放内存吗?
解决方案 »
- delphi中list的运用问题
- dll 中的多线程不能运行?
- 100分,問一個水晶報表的小問題
- 用socket连接时,怎样让服务器上数据库中的记录显示在客户端combobox1上来?
- 一个按钮的问题
- 出现ACCESS VIOLATION 后 跳到 POP EBX 是什么意思?????????
- 谁有professional stand edition 6.3安装工具?
- -=-=-=请教各位,我想在一个表上建一个外键,要在那里设置?-=-=-=-=
- ●●●●●● 请问QQ那样上下滑动的条是怎么实现的! ●●●●●●
- 注意:下载http://yts.my5599.net/soft/i1.htm源代码(一个画图软件),请用下载工具下载:推存用:网络蚂蚁。
- 有HIS医院管理系统的朋友进来看一看
- 如何象记事本那样,弹出一个查询窗口来的时候,还可以在记事本中输入文字啊?
szBuf: array[0..1024] of Char;
nLen: Integer;
end;
PBufRec = ^TBufRec;procedure TForm1.Button2Click(Sender: TObject);
var
pBuf: PBufRec;
pv: Pointer;
begin
New(pBuf);
// mov eax, $00000408 sizeof(BufRec); eax $00000408
// call @Getmem
// eax 00ce4afc
// pBuf $CE4AFC
pv := pBuf;
Dispose(pv);
// xor edx, edx 将edx清零 EDX Pointer to type info
// call @FreeMem
end;procedure TForm1.Button3Click(Sender: TObject);
var
pBuf: PBufRec;
pv: Pointer;
begin
New(pBuf);
// mov eax, $00000408 sizeof(BufRec);
// call @Getmem
pv := pBuf;
Dispose(PBufRec(pv));
// mov edx, $00000408注意: 此时edx为sizeof(BufRec) EDX Pointer to type info
// call @FreeMem
end;
因为Pointer 就是 void* 它是不能用来计算的 虽然指针的大小在win32下都是4byte的,但是它覆盖的地址空间,是不能被计算出来的.
但是 也比较奇怪 我跟踪Dispose进去 感觉上面两个事件的执行代码没什么差别,楼主说 第一种有问题, 我也只是感觉有问题,但现在看来,代码也没问题.
不过我打开任务管理器,分别运行1万次添加数据的循环,然后分别用方法1和方法2来释放内存,结果是方法1的内存只释放一部分,而方法2的内存是完全释放的。
按实际应用,我也一定选择方法2来释放内存的,只不过想深入一些了解DELPHI释放内存的机制,不过我的知识还不够,没能理解beyondtkl的代码,看看还有没有更多的讨论,2星期后结帖。
感谢楼上2位的参与。
asm
{ -> EAX Pointer to object to be disposed }
{ EDX Pointer to type info } PUSH EAX
CALL _Finalize
POP EAX
CALL _FreeMem
end;procedure _Finalize(p: Pointer; typeInfo: Pointer);
asm
MOV ECX,1
JMP _FinalizeArray
end;procedure _FinalizeArray(p: Pointer; typeInfo: Pointer; elemCount: Cardinal); // typeInfofunction _FreeMem(P: Pointer): Integer;
begin
if P <> nil then
begin
Result := MemoryManager.FreeMem(P);
if Result <> 0 then
Error(reInvalidPtr);
end
else
Result := 0;
end;
给你理了一下.....typeInfo: Pointer 这个参数很重要。。 你去System.pas P14305看看。
所以方法1不对,方法2才对
Dispose(Data)相当于释放4个字节(Pointer类型)
Dispose(PRECA(Data))则释放16个字节(TRect类型)
很明显如果用第一种方法将有12个字节的内存泄漏
s: string;
至于释放多少字节,是由指针本身分配时的大小决定的,dispose不理会这一点,它直接调用freemem,让freemem去查找指针原来分配的大小,大龙驹列出的原码已经说明了这一点如果PRECA被转换成无类型指针,则pRecA的s所分配的内存将遗漏(如果S被附值的话),但是pRecA结构所分配的内存则按其原来分配的大小被释放所以方法1将遗失所有记录的s的空间开销,但是记录的空间还是被正确释放了
dispose只是释放这个指针所占用的内存,和指针类型下的结构。
如果不指定Data指针的类型,编译器不知道指针的类型,所以就没有办法完全释放的。
个人觉得伴水说的比较对...
我们都知道FreeMem(P)中的P是可以不需要指定大小的,并且P可以是无类型指针,也就是Pointer,FreeMem也能正确释放,说明Delphi对指针保留了指针已分配空间大小的信息,这个信息存放在被指向内容的前4个字节,这可以从getmem.inc源码中看出。那么既然Dispose调用了FreeMem,所以方法1的Dispose(Data)依然能够释放TRecA所占用的空间,只是因为没有类型信息,Finalize过程不起作用,也就是TRecA.S所指向的空间的内存被泄漏了。我做了个小程序,也说明了这一点program Project1;{$APPTYPE CONSOLE}uses
SysUtils;const
MBytes = 1024 * 1024;type
TMyIntfObj = class(TInterfacedObject)
destructor Destroy; override;
end; TRec = packed record
I: IInterface;
Stub: array[1..1*MBytes-SizeOf(IInterface)] of Byte;
end;
PRec = ^TRec;
var
HS: THeapStatus;
SelfManagedObjReleased: Boolean;{ TMyIntfObj } destructor TMyIntfObj.Destroy;
begin
SelfManagedObjReleased := True;
inherited;
end; procedure Check;
var
CurrHS: THeapStatus;
MemLeak: Integer;
begin
CurrHS := GetHeapStatus();
MemLeak := CurrHS.TotalAllocated - HS.TotalAllocated;
WriteLn('Memory leak = ', MemLeak);
if not SelfManagedObjReleased then
WriteLn('Boy, you lost!')
else WriteLn('Ok, the self managed object is released.');
WriteLn;
WriteLn;
end; procedure MemBlkSzAllocatedForPtr(p: Pointer; const aPtrName: string);
//返回为一个指针分配的块的大小,>= GetMem Size + SizeOf(Integer)
const
cThisUsedFlag = 2;
cPrevFreeFlag = 1;
cFillerFlag = Integer($80000000);
cFlags = cThisUsedFlag or cPrevFreeFlag or cFillerFlag; var
SzFlags: PInteger;
Sz: Integer;
begin
SzFlags := P;
Dec(SzFlags);
Sz := SzFlags^ and not cFlags;
WriteLn('Memory block size allocated for ', aPtrName, ' = ', Sz);
end; procedure Dispose1();
var
R: PRec;
P: Pointer;
begin
WriteLn('In Dispose1()');
HS := GetHeapStatus();
SelfManagedObjReleased := False; New(R);
R.I := TMyIntfObj.Create(); P := R; //cast to untyped pointer MemBlkSzAllocatedForPtr(P, 'P'); Dispose(P); //try dispose the untyped pointer; Check();
end; procedure Dispose2();
var
R: PRec;
begin
WriteLn('In Dispose2()');
HS := GetHeapStatus();
SelfManagedObjReleased := False; New(R);
R.I := TMyIntfObj.Create(); MemBlkSzAllocatedForPtr(R, 'R'); Dispose(R); Check();
end;begin
WriteLn('SizeOf(TRec) = ', SizeOf(TRec));
WriteLn;
Dispose1();
Dispose2(); Write('Press ENTER to continue...'); Readln;
end.程序的输出:
========================================
SizeOf(TRec) = 1048576In Dispose1()
Memory block size allocated for P = 1048580
Memory leak = 12
Boy, you lost!
In Dispose2()
Memory block size allocated for R = 1048580
Memory leak = 0
Ok, the self managed object is released.
Press ENTER to continue...
========================================首先TRec的大小为1MDispose1()调用的是Dispose(P);其中P为无类型指针,如果Dispose(P);只释放4个字节的话,那么Memoryleak应该大于1M,而输出的是MemLeak = 12,说明TRec所占用的空间被释放了,而泄露的这12字节就是TMyIntfObj所占用的空间8个字节加上保存指针大小sizeFlag的4个字节。