combobox的object内存释放问题 ( 积分: 50 )

  • 主题发起人 主题发起人 rsjd
  • 开始时间 开始时间
R

rsjd

Unregistered / Unconfirmed
GUEST, unregistred user!
我在combobox的additem()方法中用一个record来记录一组值,因为这个combobox经常使用,item也经常变化,看了大富翁上的一些帖子,说是在form.onclose事件中释放内存,但因为这个combobox创建了无数次,在onclose时,我认为也只是释放最后一次创建的items.objects内存,这是不是有点问题呢?
在treeview中有一个ondeletion事件,所以可以很安全的释放内存,但combobox并没有这个事件,应该如何处理更好呢?我现在干脆一点也不去释放,用boundschecker打开exe文件运行了一下,好象并没有说有任何错误什么的,不知是我不会用boundschecker还是objects可以自动释放内存,请高手指点一下。
 
我在combobox的additem()方法中用一个record来记录一组值,因为这个combobox经常使用,item也经常变化,看了大富翁上的一些帖子,说是在form.onclose事件中释放内存,但因为这个combobox创建了无数次,在onclose时,我认为也只是释放最后一次创建的items.objects内存,这是不是有点问题呢?
在treeview中有一个ondeletion事件,所以可以很安全的释放内存,但combobox并没有这个事件,应该如何处理更好呢?我现在干脆一点也不去释放,用boundschecker打开exe文件运行了一下,好象并没有说有任何错误什么的,不知是我不会用boundschecker还是objects可以自动释放内存,请高手指点一下。
 
我觉得你在combobox的additem()方法中并没有创建什么,只是对一些对象的引用,所以不需要释放。
如果你的record记录使用了内存,那需要释放record记录的内存。与combobox无关。
 
可能我说得不太清楚,我的代码大概如下,这个Tcombo是一个对象,我现在已经可以用Tcombo(Combo1.Items.Objects[Combo1.ItemIndex]).id来使用这个值了,象我上一贴所说,我不知道应该在哪里来释放过程中mydata对象实例所占用的空间,是不是不用释放呢?

Tcombo = class
id: integer;
end;

procedure TForm1.TreeView1Change(Sender: TObject
Node: TTreeNode);
var
mydata: Tcombo;
T: TADOQuery;
i: integer;
begin
...(以上略,大致是调用不同的pagecontrol,在pagecontrol中有一个combobox,点击treeview中的节点显示,所以会多次调用本方法,也就是说会多次生成这个combobox)

T.SQL.Text := 'SELECT id, name from t1';
T.Open;
Combo1.Clear;
for i:=0 to T.recordcount-1 do
begin
mydata := Tcombo.Create;
mydata.id := T.Fields[0].AsInteger;
Combo1.AddItem(T.Fields[1].AsString, mydata);
if Node.Text = T.Fields[1].AsString then combo1.ItemIndex := i;
T.Next;
end;
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
var i:integer;
begin
for i:=0 to ComboBox1.Items.count-1 do
begin
if Assigned(ComboBox1.Items.Objects) then
ComboBox1.Items.Objects.free;
end;
end;
 
在窗口关闭时释放内存存在一个问题,我上面的代码只是演示,SQL语句并不完整,实际上,这个combobox的items并不是固定的,也就是说ComboBox1.Items.count并不总是一样,我是根据Treeview节点的不同来生成不同的查询,相当于T.SQL.Text := 'SELECT id, name from t1 where pname='+quotedstr(treeview1.selected.text),这样,FormDestroy过程只是清空最后一次items中的对象内存,并没有将以前对象mydata中的内存释放,不知我理解得对不对
 
这样也不是办法呀。你不释放看看有没有内存泄漏
 
我是这样做的:
procedure TfrmStatGuide.FreeComboxObject(var ComBox: TComBobox;
const Len: Integer);
var
I : Integer;
begin
if ComBox.Items.Count = 0 then Exit;

for I := 0 to ComBox.Items.Count -1 do
begin
if Assigned(ComBox.Items.Objects) then
begin
FreeMem(Pointer(ComBox.Items.Objects),Len);
ComBox.Items.Objects := nil;
end;
end;
end;
在装载ComboBox装载之前先释放上次的内存:
...
FreeComboxObject(ComboBox, SizeOf(Integer));
ComboBox.Items.Clear;
...
while not AdoQu.Eof do
begin
GetMem(PStat, SizeOf(Integer));
Id := AdoQu.FieldByName('id').AsInteger;
Move(Id, PStat^, SizeOf(Integer));
ComboBox.Items.AddObject(AdoQu.FieldByName('Desc').AsString, TObject(PStat));
frmMain.Progress.Progress := frmMain.Progress.Progress + 1;
AdoQu.Next;
end;
别忘了最后在窗口注销的时候再释放一次:
procedure TfrmStatGuide.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
FreeComboxObject(cmbStatType, SizeOf(Integer));
end;
 
procedure TForm1.TreeView1Change(Sender: TObject
Node: TTreeNode);
var
mydata: Tcombo
//局部变量
T: TADOQuery;//局部变量
i: integer;
begin
...(以上略,大致是调用不同的pagecontrol,在pagecontrol中有一个combobox,点击treeview中的节点显示,所以会多次调用本方法,也就是说会多次生成这个combobox)

T.SQL.Text := 'SELECT id, name from t1';
T.Open;
Combo1.Clear;
for i:=0 to T.recordcount-1 do
begin
mydata := Tcombo.Create;//创建了后没有释放
mydata.id := T.Fields[0].AsInteger;
Combo1.AddItem(T.Fields[1].AsString, mydata);
if Node.Text = T.Fields[1].AsString then combo1.ItemIndex := i;
T.Next;
//会有内存泄露
//mydata和T
关闭了窗口mydata和T所占的内存并没有释放掉。关闭了程序后才可释放
end;
end

Delphi 的类是引用类型,存放在堆中,每个应用程序可以获得的内存空间分为两种:堆(heap)和栈(stack)。 堆中的内存空间的分配与释放是必须由程序员来控制的。
栈中的内存空间的分配与释放是由编译器和系统自动完成的,不需要程序员过问。函数调用时按值传递的参数所占空间、函数中的局部变量等,都是在栈中被分配空间的。
引用类型都存放在堆中
 
每次 Combo1.Clear 之前释放当时的 Objects。
关闭窗体时再最后释放一次。
 
多人接受答案了。
 
后退
顶部