该死的clear 根本不释放内存,怎么才能释放泛型LIST的内存?

程序的内存一直不停的涨,用其他工具也查了有泄露但是是定位到进程创建的时候,总觉得很奇怪
后来查了资料
delphi的clear对内存是不释放的
因为我的程序在调用的很多 过程冲不断的clear,数据要不断的更新
clear的都是 tstringlist ,还有很多的结构体泛型的list,里面有string类型的,查看内存的时候 发现里面的内存一直不停的增长。问题是这样的
1 对于 tstringlist和泛型list应该怎样清理里面的数据 并且释放内存(释放里面的空间)。但是不需要重新去creat(不是彻底的把它销毁 还是可以使用这个泛型的list的,但是里面是空的,可以继续装数据进去),而且也不出现读写错误。
查资料的时候 发现 这么一段话
Plain Text code
?
1
关于TList.Clear释放内存 一直以来被TList.Clear是否会释放每个Item的内存纠结,今天终于找到确切的答案了:不会释放,所以要释放每个Item指向的内存块,还是需要自己老老实实用循环Free掉或者Dispose掉

2、因为的我程序内存不停的涨,而且工具定位出来的位置都是在创建的地方,所以很难真正定位到泄露的位置,而且这些数据是希望程序真正退出之后才完全释放的。(中间有很多 clear add操作)应该怎么写? 
分数有限,希望能够有人回复,只要解释清楚或者有代码说明就可以。

感谢回复。

Clear 只是清除了项中的内容,其中的对象并没销毁。请看DELPHI的实例:
procedure TForm1.FormButton1Click(Sender: TObject);

type
  PMyList = ^AList;
  AList = record
    I: Integer;
    C: Char;
  end;

var

  MyList: TList;
  ARecord: PMyList;
  B: Byte;
  Y: Word;
begin
  MyList := TList.Create;
  try
    New(ARecord);
    ARecord^.I := 100;
    ARecord^.C := 'Z';
    MyList.Add(ARecord); {Add integer 100 and character Z to list}
    New(ARecord);
    ARecord^.I := 200;
    ARecord^.C := 'X';
    MyList.Add(ARecord); {Add integer 200 and character X to list}

    { Now paint the items onto the paintbox}
    Y := 10;             {Variable used in TextOut function}

    for B := 0 to (MyList.Count - 1) do
    begin
      ARecord := MyList.Items[B];
      Canvas.TextOut(10, Y, IntToStr(ARecord^.I)); {Display I}
      Y := Y + 30;  {Increment Y Value again}
      Canvas.TextOut(10, Y, ARecord^.C);  {Display C}
      Y := Y + 30;  {Increment Y Value}
    end;

    { Cleanup: must free the list items as well as the list }
   for B := 0 to (MyList.Count - 1) do
   begin

     ARecord := MyList.Items[B];
     Dispose(ARecord);
   end;
  finally
    MyList.Free;
  end;
end;

跟进源码里看看就知道了啊
tstringlist从strings继承,strings 是个抽象类,clear是它的抽象方法,由其子类来负责实现clear,你可以自己覆盖clear,在其中做释放内存的工作,但顾名思义tstringlist只是string的容器,string和intert、double...这些简单类型一样,都是由系统维护它们的引用记录来自动管理其生命周期的,不用人为干预。

tlist的clear是个虚函数。
procedure TList.Clear;
begin   // 基类实现中没有且也不应该负责清理item分配的内存
  SetCount(0); 
  SetCapacity(0);
end;

你应该在其析构函数中处理item的内存清理工作,如果你要clear时也清理内存,就上面说的自己重写覆盖clear函数,在里面做清理。

我一般这样子释放:

  for m := 0 to ls.Count - 1 do 
     Dispose(PExit(ls[m]));

  ls.Clear();
  ls.Free();

如果List里面是指针的话,需要单独释放每个item内容,然后再clear


PExit是自己定义的么。我没找到这个函数的过程。
还有 Dispose 需要指针类型的,直接给结构体导致编译不通过
间接赋值再释放导致出现数据访问错误的问题。。

 begin

     ARecord := MyList.Items[B];
     Dispose(ARecord);-----这里编译器提示 ARecord不是指针类型。delphi 2010的
   end;
  finally
    MyList.Free;
  end;
end; 


弄个简单的重写Tlist.Clear满足你需求的例子(非泛型,当然泛型更是方便了)
另外俺不是撸大师,请教俺撸同学,要保证鲁棒性必须清晰把握对象的生命周期

Delphi/Pascal code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
unit  Unit1;
 
interface
 
uses
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, StdCtrls;
 
type
   // 继承Tlist并重写Clear方法
   TMyList =  class (TList)
   public
     procedure  Clear; override;
   end ;
   // 自定义个类型做为item,测试用
   TMyClass =  class (TInterfacedObject)
   public
     FMeb:  Integer ;
   end ;
 
   TForm1 =  class (TForm)
     btn1: TButton;
     procedure  btn1Click(Sender: TObject);
     procedure  FormDestroy(Sender: TObject);
     procedure  FormCreate(Sender: TObject);
   private
   public
   end ;
 
var
   Form1: TForm1;
 
implementation
 
{ $R  *.dfm}
 
var
   li: TMyList;
 
procedure  TForm1 . btn1Click(Sender: TObject);
var
   m: TMyClass;
const
{ $J +} count:  Integer  0 ; { $J -}
begin
   m := TMyClass . Create;
   Inc(count,  1000 );
   m . FMeb := count;
   li . Add(m);
   // 可以观察到li.count是否正常,且item内容是否正确访问到
   Caption := Format( 'li.count=%d; li.items[li.count-1]=%d' , [li . Count, TMyClass(li . Items[li . Count -  1 ]).FMeb]);
   //li.Clear; 销毁list所有item, 可去掉注释猛击按钮观察count的值始终为1,且也没有泄露内存
end ;
 
{ TMyList }
 
procedure  TMyList . Clear;
var
   I:  Integer ;
begin
   // 倒叙遍历items确保安全访问index
   for  I := Count -  1  downto  0  do
   begin
     // 通过多态销毁item
     // 如果想使用 is、as 操作符,得实现Iinterface接口
     TMyClass(Items[i]).Free;
   end ;
   inherited ;
end ;
 
procedure  TForm1 . FormCreate(Sender: TObject);
begin
   li := TMyList . Create;
end ;
 
procedure  TForm1 . FormDestroy(Sender: TObject);
begin
   li . Free;  //销毁list自身,free中会调用析构函数destroy,destroy中调用了clear
end ;
 
end .
procedure  TForm1 . FormButton1Click(Sender: TObject);
 
type
   PMyList = ^AList;
   AList =  record
     I:  Integer ;
     C:  Char ;
   end ;
 
var
 
   MyList: TList;
   ARecord: PMyList;
   B:  Byte ;
   Y:  Word ;
begin
   MyList := TList . Create;
   try
     New(ARecord);
     ARecord^.I :=  100 ;
     ARecord^.C :=  'Z' ;
     MyList . Add(ARecord);  {Add integer 100 and character Z to list}
     New(ARecord);
     ARecord^.I :=  200 ;
     ARecord^.C :=  'X' ;
     MyList . Add(ARecord);  {Add integer 200 and character X to list}
 
     { Now paint the items onto the paintbox}
     Y :=  10 ;              {Variable used in TextOut function}
 
     for  B :=  0  to  (MyList . Count -  1 do
     begin
       ARecord := MyList . Items[B];
       Canvas . TextOut( 10 , Y, IntToStr(ARecord^.I));  {Display I}
       Y := Y +  30 ;   {Increment Y Value again}
       Canvas . TextOut( 10 , Y, ARecord^.C);   {Display C}
       Y := Y +  30 ;   {Increment Y Value}
     end ;
 
     { Cleanup: must free the list items as well as the list }
    for  B :=  0  to  (MyList . Count -  1 do
    begin
 
      ARecord := MyList . Items[B];
      Dispose(ARecord);
    end ;
   finally
     MyList . Free;
   end ;
end



你这个代码是一个组件里面 这样写虽然可以完全释放,可是使用时间太短了
我的要求是在窗体创建的时候创建,窗体运行的时候 节约内存空间(free的话导致内存不断上升),不能导致内存泄露,窗体销毁的时候彻底释放空间。你这个创建和销毁只在一个组件里面,这样意义很小。我的目的是如果在调用的过程里面泛型数组动态的增加,又不停的clear(clear不真正的清理空间)的时候 能够真正的清理空间减少程序内存的占用,窗体销毁的时候能够真正的彻底的销毁泛型list,中间不出现没有找到指针这样的提示(应该是释放多次的缘故,有些在创建之后使用它就不会提示,有些创建之后不使用就提示,但是因为使用不使用是在软件里面的一个设置,)
还有鲁过的代码我看不明白。希望鲁过师傅+我关注,我们多聊聊。项目最后快收尾了。这个内存泄露的问题是最后的几个重要问题,对于项目的收尾和验收有重要意义。希望鲁过师傅多多帮助。


我用的是delphi  2010 而且我的 list是泛型的,没有办法那样释放

Delphi/Pascal code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
procedure  TForm1 . FormDestroy(Sender: TObject);
  var   I:  Integer begin   // TForm1销毁时 销毁list   
if  Assigned(List)  then  
begin    
for  I := List . Count -  1  downto  0  do    
begin      
FreeMemory(list . Items[i]); -------这里提示编译不通过 要求是指针      
// FreeAndNil(list); 放到下面     
end ;   
end ;    
FreeAndNil(list);  
end ;   
这样,即便仅仅create,最后销毁也不会有漏网的 
  
procedure  TForm1 . FormCreate(Sender: TObject);  var   gl, gl2: pGamelist;
  begin   List := TList < pGamelist > .Create;   
//gl := GetMemory(SizeOf(TGamelist));   
//gl2 := GetMemory(SizeOf(TGamelist));   
//gl^.sky := 1000;   
//gl2^.sky := 2000;   
//List.Add(gl);     
// 添加两项   
//List.Add(gl2);
  end

我采用的方法是 
categroyList.retainAll(categroyList);
categroyList.clear();

你可能感兴趣的:(Delphi)