♣
[求助]关于用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过程正常释放内存吗?
· 网友精彩回答:
做法1可以正常释放内存
dispose(preca(listview1.items.item[i].data));//做法2
这样应该是比较稳妥的做法, 看汇编代码:
tbufrec = record
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进去 感觉上面两个事件的执行代码没什么差别,楼主说 第一种有问题, 我也只是感觉有问题,但现在看来,代码也没问题.
in system.pas
procedure _dispose(p: pointer; typeinfo: pointer);
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); // typeinfo
function _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看看。
编译器不会知道你的data的原来是什么类型的指针的,必须显式告诉编译器,
所以方法1不对,方法2才对
理论上我觉得应该没什么区别...
可能性是,在只指定一个pointer去释放内存时,delphi可能只是把pointer释放,而实际的内存块在变量表中还有一个指明的type - treca被引用(因为你在create的时候没有handle它,delphi可能会有在变量表中handle它), 而指定type后,在释放时delphi会查找引用此内存块的变量表中的handle,然后释放该内存...
没有找到深层的内存管理资料..sorry.
高手就是高手
我怕下一步连01也搬过来了
帮你顶下,大哥给我5分,我要求不高
dispose()需要通过参数指针的类型判断释放空间的大小
dispose(data)相当于释放4个字节(pointer类型)
dispose(preca(data))则释放16个字节(trect类型)
很明显如果用第一种方法将有12个字节的内存泄漏
楼上讲解好清楚啊! 又学习到一点.
zswang的说法也不对,dispose需要类型信息主要是为了清除结构的生存期自管理对象,就是例中的
s: string;
至于释放多少字节,是由指针本身分配时的大小决定的,dispose不理会这一点,它直接调用freemem,让freemem去查找指针原来分配的大小,大龙驹列出的原码已经说明了这一点
如果preca被转换成无类型指针,则preca的s所分配的内存将遗漏(如果s被附值的话),但是preca结构所分配的内存则按其原来分配的大小被释放
所以方法1将遗失所有记录的s的空间开销,但是记录的空间还是被正确释放了
记得前一段时间讨论过类似的问题
dispose只是释放这个指针所占用的内存,和指针类型下的结构。
如果不指定data指针的类型,编译器不知道指针的类型,所以就没有办法完全释放的。
个人觉得伴水说的比较对...
data指针本是占用的内存有list释放,但是data指向的东西由freemem释放,data所指向的结构内的生存期自管理对象则由finalize负责清除,释放data所指向的东西是不需要类型信息的
其实很简单,我们平常总是getmem(p, x); freemem(p);这样用
我们都知道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) = 1048576
in 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的大小为1m
dispose1()调用的是dispose(p);其中p为无类型指针,如果dispose(p);只释放4个字节的话,那么memoryleak应该大于1m,而输出的是memleak = 12,说明trec所占用的空间被释放了,而泄露的这12字节就是tmyintfobj所占用的空间8个字节加上保存指针大小sizeflag的4个字节。
- 更多问题:
- · 配ODBC
- · DWORD nByteswritten(0);这个什么意思?
- · UDP数据包大小问题?
- · 比如我的IP是60.176.32.36,那我在IE地址栏里输入//60.176.32.36,怎么跳出来一个对话框要我输入用户名和密码,到底咋回事?
- · 找socketserver原码
- · 比较难的问题:Eclipse和重构高手进
- · 在提交了一次add后,选择列表中的中文都变成了"????????",为什么?
- · 100分求解UDP控件的奇怪问题,解决就给分。
- · 关于PB中英文翻译的文章(2天类结帖)(前天的帖子刚结帖了)
- · VC+ACCESS数据库程序的问题。
- · 请问到哪里可以下载 程序员修炼三部曲 非常感谢
- · 在线等,请问后缀是WDL的文件该用什么工具打开?
- · 网络编程中的connect函数怎么控制它的connect时间
- · 自己下了个CPU降温工具CPUCOOL,但是不大会用,来请教一下.
- · 100分求一软件:无届浏览器
- · 怎样操作一组单选框中某一个框
- · Request技术文档
- · Browser技术文档 | Browser
- · 性能服务与管理
- · Stream技术文档
- · 表单技术与应用 | 表单
- · 排序的思路和应用
- · erp管理
- · php soap
- · soap消息
- · soap header
- · jdk1.4
- · jdk的配置
- · 内存芯片
- · 电源芯片
- · 甲骨文总裁
- · lotus notes 开发
- · 什么是数据库软件
- · 数据库管理系统
- · 数据库课程设计报告
- · 炮轰网站数据库
- · 数据库实例
- · 数据库服务器的安全
- · 破解Access数据库密码
- · powerpoint课件
- · 最新firefox

