结构体类似如下:RRecord = record
EndTime :TDateTime;
StartTime :TDateTime;
i1 :integer;
i2 :integer;
i3 :integer;
i4 :integer;
i5 :integer;
i6 :integer;
s1 :string;
s2 :string;
s3 :string;
end;假设情况如下:
某时刻程序动态申请内存空间 “GetMem(p, sizeof(RRecord)); ” 。
然后程序有这样的赋值操作 :
p.s1 := ......; p.s2 := ......; p.s3 := ......;
代码跑了一段时间,释放申请的内存空间,程序这样做 :
FreeMem(p, sizeof(RRecord)); 请问 FreeMem 时 ,原本里面的s1,s2,s3会自己自动释放么??还是说到程序退出时才自动释放??
需要自己手动释放么??如何释放??
EndTime :TDateTime;
StartTime :TDateTime;
i1 :integer;
i2 :integer;
i3 :integer;
i4 :integer;
i5 :integer;
i6 :integer;
s1 :string;
s2 :string;
s3 :string;
end;假设情况如下:
某时刻程序动态申请内存空间 “GetMem(p, sizeof(RRecord)); ” 。
然后程序有这样的赋值操作 :
p.s1 := ......; p.s2 := ......; p.s3 := ......;
代码跑了一段时间,释放申请的内存空间,程序这样做 :
FreeMem(p, sizeof(RRecord)); 请问 FreeMem 时 ,原本里面的s1,s2,s3会自己自动释放么??还是说到程序退出时才自动释放??
需要自己手动释放么??如何释放??
解决方案 »
- 多线程问题
- 网络监控 撒分啦
- stringtest:=Table1.FieldValues['A1'].AsString; 出现了"variant does not reference an automation object",这个错误?
- Delphi2006Copyfile调用后不能删除原文件,急!!
- dll问题:无法定位程序输入点*****于动态连接库***上。
- 如何使一个窗体总是在另一个窗体之前?
- BORLAN DATABASE ENGINEP初始化错误如何解决???
- 很简单的问题,请大家帮忙
- delphi断点问题
- 怎样实现在DBGRID中单击右键弹出弹出式菜单?
- 问一个关于DevExpress皮肤的问题
- 求助treeview.node.data
FreeMem(p, sizeof(RRecord));//释放了s1,s2,s3所需的内存空间。所以是不用的。
如果是用
New和Dispose则不用
SetLength(P.s1 , 10 * 1024*1024);
PByte(P.s1)^ := 0;
ShowMessage('看看程序使用的内存,应该>10M');
FreeMem(P);
ShowMessage('现在看看程序使用的内存,应该还是>10M');
然后换成这样
New(p);
SetLength(P.s1 , 10 * 1024*1024);
PByte(P.s1)^ := 0;
ShowMessage('看看程序使用的内存,应该>10M');
Dispose(P);
ShowMessage('现在看看程序使用的内存,应该明显减少了10M');或者这样
GetMem(p, sizeof(RRecord));
SetLength(P.s1 , 10 * 1024*1024);
PByte(P.s1)^ := 0;
ShowMessage('看看程序使用的内存,应该>10M');
P.s1 := ''; //把字符串释放掉
FreeMem(P);
ShowMessage('现在看看程序使用的内存,应该明显减少了10M');
type
R = record
I: Integer;
S: string;
end;procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(string(Tag));
end;procedure TForm1.FormCreate(Sender: TObject);
var
P: ^R;
begin
GetMem(P, SizeOf(R));
P^.I := 1;
P^.S := 'abc';
Tag := Integer(P^.S);
ShowMessage(P^.S);
//P^.S := '';//如果这里没有手动释放,则点击Button1时,还是会显示abc。从调试状态下的汇编代码中也不会看到用来释放字符串的LStrClr。
FreeMem(P, SizeOf(R));
end;
你的方法测试不完全对,不能拿字符串常量来测试这个
给你看个例子:var
D : integer;procedure TestProc1;
var
S : AnsiString;
begin
S := 'abcdefghijklmn'; //这里并未复制一个,而是给常量字符串的引用+1
D := Integer(S);
S := ''; //引用-1,并未释放 abcd...占的内存,实际上释放不了,它在只读内存区,靠
end;procedure TestProc2;
var
S : AnsiString;
begin
SetLength(S , 20); //生成一个全新的字符串,一定是全新的从堆上分配的.
S := 'abc' + S;
D := Integer(S);
S := ''; //这里就真正释放了,所以后面调用D要出错.
end;procedure TForm1.Button1Click(Sender: TObject);
begin
TestProc1;
ShowMessage(AnsiString(D)); //这个不出错,但是显示的是 abcdefghijklmn
TestProc2;
ShowMessage(AnsiString(D)); //这个就要出错了.
end;这虽然不是Delphi本身的问题,但是Delphi确实存在常量字符串的问题,而且从出生到现在一直有包括Delphi2010
XE/XE2没作测试
string 自动释放要 时机
在一个函数内用到 那么在这个函数内是不会自动释放的
完成这个函数后 才会检测释放
程序本着谁申请谁释放的原则,如果用GetMem,回过头来看代码的时候,一定要找FreeMem.容易忽略Dispose
我当时就看调试状态的汇编代码了,我的那段代码会调用LStrAsg,跟进去会发现NewAnsiString,继续跟进去会执行到GetMem,证明确实生成字符串了——所以这儿的字符串常量用来测试没问题!
不知道Delphi7是不是也是这样。
var
S : AnsiString;
begin
S := 'abcdefghijklmn';
PByte(S)^ := 0; //出错,证明未复制新串,D7,D2010是这样,2007未测试,下班了,
既然在只读内存区,那为什么引用计数可以修改?在S := 'abcdefghijklmn'之后,引用计数变成了0,之前是-1.
procedure _LStrClr(var S);
MOV ECX,[EDX-skew].StrRec.refCnt { fetch refCnt }
DEC ECX { if < 0: literal str }
JL @@done //常量字符串到这里就跳转了
......
@@done:
但是呢 你这样测试 不够准确 这个观点我还是坚持,至于你测出的结果与事实对于不对,我就不知了,我承认没深入了解
s11ss 的测试 在另一个button 事件里 显示信息 从语义上来说 比较准确
语义准确了 并不代表测试的结果也会正确!
你只要了解为什么出现 FreeAndNil 这个函数,大概就知道为什么了对于引用计数的机制
我的理解是:系统在某个时刻,进行全局扫描,打引用计数为0的内在释放
那是在什么时刻比较好呢 ?据说是处理完本次事件的下一次事件开始
关于string 类型 找到一篇文章
共同学习下
http://www.cnblogs.com/zhengjuzhuan/archive/2010/03/15/1686257.html
f1:string;
f2: variant;
f3: IInterface
end;...
var
p:^t1;
begin
new(p); //这句等价于 Getmem(p,sizeof(t1)); Initialize(p^);
dispose(p); //这句等价于 Finalize(p^),FreeMem(p,sizeof(t1));
...对于string,variant,inteface这三种“号称”内存自管理的变量类型,Getmem和FreeMem太低阶了,不会顾及他的一些引用计数。
里 说得很清楚 推荐这文章
反正 结果就是 FreeMem 要手功释放 Dispose不用