TListBox组件的那个AddObject函数,用于保存一个数字很方便,因为Object参数本来就是一个指针,说白了本来就是数字,所以AddObject('字符',TObject(12)),以后,需要取出数字直接Integer(Objects[...])即可,不必去释放所谓的Object对象,因为根本没对象创建。但是我要保存一个record记录就麻烦了,所以考录到了TObject对象,下面是一些方法:(1)、保存record的指针,发现record不做全局变量会丢失数据
type
TRecord=record
a,b:Integer;
end;
var t:TRecord;
begin
t.a :=100;
t.b :=100;
ListBox1.Items.AddObject('测试',TObject(@t));//<--此处无法保存数据,因为变量t的指针是临时的。(2)、使用TObject对象
type
TMyObject=class(TObject)
public
a,b:Integer;
end;......
var obj:TMyObject;
begin
obj :=TMyObject.Create;
obj.a :=100;
obj.b :=100;
ListBox1.Items.AddObject('测试',obj);
end;数据是保存了,但是突然纠结起来了,TMyObject对象需要释放吗?就好像TRecord记录是否需要释放一样模糊起来了,大家看Delphi的TObject的源代码,几乎没有一处做了任何实质性的工作,Create是空的,Destory是空的,那么TObject对象需要释放吗?
type
TRecord=record
a,b:Integer;
end;
var t:TRecord;
begin
t.a :=100;
t.b :=100;
ListBox1.Items.AddObject('测试',TObject(@t));//<--此处无法保存数据,因为变量t的指针是临时的。(2)、使用TObject对象
type
TMyObject=class(TObject)
public
a,b:Integer;
end;......
var obj:TMyObject;
begin
obj :=TMyObject.Create;
obj.a :=100;
obj.b :=100;
ListBox1.Items.AddObject('测试',obj);
end;数据是保存了,但是突然纠结起来了,TMyObject对象需要释放吗?就好像TRecord记录是否需要释放一样模糊起来了,大家看Delphi的TObject的源代码,几乎没有一处做了任何实质性的工作,Create是空的,Destory是空的,那么TObject对象需要释放吗?
你的方法1中,可以定义一个结构指针,然后New
type
PRecord=^TRecord;
TRecord=record
a,b:Integer;
end; var t:PRecord;
begin
new(t);
t.a :=100;
t.b :=100;
ListBox1.Items.AddObject('测试',TObject(@t));
不过,相应的,这个也要释放,需要dispose(xxxx);
那么,当在 TForm1 下建立 TMyObject.Create(Self),
最后它会自动释放。
详见《inside vcl 深入VCL架构剖析》第二章的2-6节,具体在79页2:
详见《inside vcl 深入VCL架构剖析》中的第三章的3-2节,具体在“place holder方法”段。delphi的对象的实例都是在堆中申请内存创建的,堆中的对象的生命周期跟全局变量的生命周期一样,都是跟程序的生命周期一致的。只有在栈中申请的内存才会随清栈工作时自动回收。
重申,create的对象一定要free,free的工作可以自己做也可以委托其他对象做,但必须明确自定确实做了free。
InstanceSize 是Class 函数,Class 函数是不需要创建对象即可使用,即:TObject.InstanceSize也是可以的,而且InstanceSize函数在TObject类里面没有哪个非class 函数使用它。突然感觉TObject对象很奇怪,它的代码太少了,几乎没什么可看,能看的有看不懂,全是汇编。大家记得CheatEngine源代码吗,就使用了这种方式,创建了TObject对象并AddObject,但是又不释放。如果能有内存泄露查看工具看一下,就知道不释放TObject对象是否会引起内存泄露。
TmyCls = class(TComponent)
private
fName: string;
procedure setName(s:string);
published
property Name:string read fName write setName;
end;procedure TmyCls.setName(s: string);
begin
if s<>'' then
fName:=s;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Tobj: TmyCls;
begin
Tobj := TmyCls.Create(Self);
Tobj.Name := 'Hello world';
ShowMessage(Tobj.Name);
{Tobj.Free;}//不用释放由Owner回收,不建议这样,最终由Owner关闭时回收
end;
这个应该是,对象创建时即默认全局对象,即使它在一个函数内临时创建,但是被AddObject使用它后会继续延续,这和Record记录完全不一样,Record记录不申请为全局变量,它只在函数内有效,函数外被释放,事实证明也是这样。
InstanceSize 是Class 函数,Class 函数是不需要创建对象即可使用,即:TObject.InstanceSize也是可以的,而且InstanceSize函数在TObject类里面没有哪个非class 函数使用它。突然感觉TObject对象很奇怪,它的代码太少了,几乎没什么可看,能看的有看不懂,全是汇编。大家记得CheatEngine源代码吗,就使用了这种方式,创建了TObject对象并AddObject,但是又不释放。如果能有内存泄露查看工具看一下,就知道不释放TObject对象是否会引起内存泄露。
肯定是泄露了,有什么好怀疑的。说到检测内存的工具,EurekaLog 是第一神器,可以搜搜看看它如何用。
还有一个就是fastmm。如果你用的是delphi2007及以上版本,可以简单地program Project1;uses
Forms,
Unit1 in 'Unit1.pas' {Form1};{$R *.res}begin
Application.Initialize;
ReportMemoryLeaksOnShutdown:=True; // 加入该行,在程序运行并关闭后会提示你什么对象在哪里泄露了
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
而且似乎你有点混淆
var
pInt: ^integer
int: integer;
begin
int:= 100; // int 是值类型的100
getmem(pInt,4); // pInt 是指针,在堆中分配了4字节内存
freemem(pInt); // pInt需要手动释放,而int不需要,它在栈中创建,函数结束就自动清栈一并销毁
end;
public
path: string;
end;
........
var
fullpath: Tpathspecifier;
............
fullpath:=Tpathspecifier.Create;
fullpath.path:=opendialog1.filename;
clbPlugins.Items.AddObject(extractfilename(opendialog1.FileName)+':'+pluginname,fullpath);
..........
Tpathspecifier(clbPlugins.Items.Objects[clbplugins.ItemIndex]).Free;另外请教9楼兄弟,我用Delphi7,没用Delphi2010,主要是2010对String申明相关改变,导致我的老工程很多String都要重新申明。Delphi7用什么内存泄露工具检测?
你可以用 TMyComponent.Create(ListBox)来确保它随ListBox释放
最新版Delphi,
TStringList.Create时可以传入一个参数,
使StringList负责Object的释放。所以,利用TComponent的机制释放TMyObject,
无所谓好或不好,
只看能否解决问题。