我做了一个简单的例子,释放一个结构指针时并不需要指针类型
但是前一段时间做一个项目里,没指定指针类型释放就造成了内存泄漏
后来修改为指定指针类型的释放就没有问题了所以现在有点迷惑了,到底需要不需要指定指针类型?
或者是有的情况下需要有的情况下不需要?
请各位高手谈谈经验.

解决方案 »

  1.   

    需要,Dispose调用的是System._Dispose:
    procedure _Dispose(p: Pointer; typeInfo: Pointer);
    不提供原型的话,Finalize(System._Finalize)将无法得到正确的类型信息,对于string、动态数组等类型将没法清理没leak的record里肯定是没有string和动态数组类型的,有leak的record里至少有两者之一
      

  2.   

    // 这是Disponse的汇编代码,调用了FreeMem
    Unit1.pas.192: Dispose(TL[I]);
    0048D465 8BD3             mov edx,ebx
    0048D467 8B4640           mov eax,[esi+$40]
    0048D46A E88901F9FF       call TList.Get
    0048D46F 33D2             xor edx,edx
    0048D471 E80657F7FF       call @FreeMem// 下面是FreeMem的汇编代码
    00402B7C 53               push ebx
    00402B7D 85C0             test eax,eax
    00402B7F 7415             jz +$15
    00402B81 FF1544E04800     call dword ptr [MemoryManager + $4]
    00402B87 8BD8             mov ebx,eax
    00402B89 85DB             test ebx,ebx
    00402B8B 740B             jz +$0b
    00402B8D B002             mov al,$02
    00402B8F E838010000       call Error
    00402B94 EB02             jmp +$02
    00402B96 33DB             xor ebx,ebx
    00402B98 8BC3             mov eax,ebx
    00402B9A 5B               pop ebx
    00402B9B C3               ret 贴上来看是不是有用.
      

  3.   

    我们先看下面的例子,这个示例会提示有一个内存泄露(Delphi 2009下面是UnicodeString)program Console;{$APPTYPE CONSOLE}uses
      Fastmm4,
      SysUtils;type
      PPerson = ^TPerson;
      TPerson = record
        Name: string;
        Age: Integer;
      end;var
      s: string;
      p: Pointer;begin
      try
        s := 'Bob';
        GetMem(p, SizeOf(TPerson));
        Initialize(p);
        PPerson(p).Name := s;
        Dispose(p);
      except
        on e: Exception do
          Writeln(e.Classname, ': ', e.Message);
      end;
    end.
      

  4.   


    GetMem要和FreeMem配对
    New和Dispose配对
      

  5.   

    动态数组就不用Dispose来释放了,用SetLength(xxx, 0)一般Dispose就用来释放简单指针(New出来的),简单指针应该不用指定类型吧?
      

  6.   

    上面的例子中为什么会出现内存泄露,我相信明眼人一下子就能看出来。我们来看看这几个内存管理“函数”:GetMem和FreeMem;New和Dispose。GetMem  负责向内存管理器申请一块固定大小的存储空间,且没有初始化(Initialize)
    FreeMem 让内存管理器释放之前申请的存储空间,且没有清理(Finalize)既然GetMem和FreeMem已经能申请和释放内存了,那为什么还需要New和Dispose呢?
    答案很简单,由于Delphi的某些基本类型(如字符串、动态数组、Record、Array、Interface等)是由编译器自动管理生命周期或引用计数,所以必须在内存申请成功后初始化内存,并且保证在释放内存前完成清理动作(比如减少字符串的引用计数)。可以说,New/Dispose只是封装了GetMem/FreeMem,并做了初始化/清理动作。上面的例子中,执行PPerson(p).Name := s; 之后,s字符串的引用计数已经变成了2,如果这个时候直接调用FreeMem并没有减少s的引用计数,从而导致内存泄露。说到这里,顺便补充一下,正如二楼Seamour所说,如果你传给Dispose的是无类型指针(Pointer),编译器就不知道如何清理(无类型信息),也不会去调用Finalize,效果就和直接调用FreeMem一样。
      

  7.   

    @Harryfin一般来说,是应该把New和Dispose配对使用的,这里主要是为了说明无类型指针(Pointer)
      

  8.   

    dispose需要类型信息主要是为了清除结构的生存期自管理对象,就是例中的   
      s:   string;   
      至于释放多少字节,是由指针本身分配时的大小决定的,dispose不理会这一点,它直接调用freemem,让freemem去查找指针原来分配的大小,大龙驹列出的原码已经说明了这一点  
    这个是我从别的贴子里找到的一段话(http://topic.csdn.net/t/20050605/15/4060604.html),我觉得他说的好像有点道理,看Dispose的汇编代码,它好像也只调用了FreeMem,没有给FreeMem说明是什么类型的指针.
      

  9.   

    都说了Dispose调用的是System._Disopse,想知道它做什么了只要看rtl源代码就知道了procedure _Dispose(p: Pointer; typeInfo: Pointer);
    {$IFDEF PUREPASCAL}
    begin
      _Finalize(p, typeinfo);
      FreeMem(p);
    end;
    {$ELSE}
    asm
            { ->    EAX     Pointer to object to be disposed        }
            {       EDX     Pointer to type info            }        PUSH    EAX
            CALL    _Finalize
            POP     EAX
            CALL    _FreeMem
    end;
    {$ENDIF}不需要调用_Finalize的只调用了FreeMem,这只能说明delphi的编译器还不至于蠢到涉及底层还要多调用一次没用的函数的程度,虽然跟ms的比已经够笨的了
      

  10.   

    需要的。用FastMM4来检查就知道了。
      

  11.   


    呵呵,他说的没错,只不过你理解错了。内存管理器只负责分配和释放内存(存储空间),(我猜)它会记录所分配的内存的位置、大小和是否释放的标志。如果这块内存上面有其他的“引用”类型变量(如字符串变量、接口等),就需要使用Dispose(Dispose会调用Finalize)来完成清理动作。