delphi.memory.分配及释放---New/Dispose, GetMem/FreeMem及其它函数的区别与相同

我估摸着内存分配+释放是个基础函数,有些人可能没注意此类函数或细究,但我以为仍是弄明白的好。函数

 

介绍下面内存函数前,先说一下MM的一些过程,如不关心可忽略:spa

 1 TMemoryManager = record
 2   GetMem: function(Size: Integer): Pointer;
 3   FreeMem: function(P: Pointer): Integer;
 4   ReallocMem: function(P: Pointer; Size: Integer): Pointer;
 5 end;
 6 
 7 var
 8   MemoryManager: TMemoryManager = (
 9     GetMem: SysGetMem;
10     FreeMem: SysFreeMem;
11     ReallocMem: SysReallocMem);

 

      以上是D7版本的MM函数,其中变量MemoryManager我称为MM函数,请注意。指针

      D2005-D2007以上版本(不确认哪一个版本),MM函数多了AllocMem及RegisterLeak/UnRegisterLeak函数,与本文无关,就很少说了。调试

      第三方MM接管的就是这MM的几个函数,达到外挂目地,而Sys打头的SysGetMem, SysFreeMem, SysReallocMem则为自己系统自带的MM处理。code

 

一:New/Disposeblog

     此两函数,估计学delphi/pascal,就知道:为record/object此类数据进行分配和释放内存块进程

     而后分配与释放是调用的是GetMem/FreeMem函数,与GetMem/FreeMem不一样之处是:内存

        New()在GetMem后,进行了initialize(x)操做,即对record/object的数据进行初始化的操做.string

       initialize函数,在system单元,该函数说白了,即对record/object里面中,含有string,interface, dync array,variant,record,array的字段,进行初始化为0(清空).it

     这一步很重要,由于GetMem返回的内存块可能重复使用过的,使用过的,表示有值。

     有值的状况下,再从新赋值,就表示旧地址对应的数据要先清空,清空随机地址的数据?AV就会出现了...

     (不要想着,在GetMem后,进行每字段初始化,容易出错的就是这个,在有以上以字段的状况下,若是须要手动初始化,必须用fillchar,缘由如上。) 

     与之相反的Dispose()亦同,反操做,进行清空:finalize(x)后,再进行FreeMem,以保证record/object中,

     string,interface/dyncarray字段,不会由于直接调用FreeMem而泄露(leak)

 

     总结是:

       a: New==> GetMem(p, sizeof(TDataType)) + Initialize(p^) ==>AllocMem(sizeof(TDataType));

           它与AllocMem区别是:initialize(x)不会对每一个字节清0,只针对于某些字段清0.

           Dispose == Finalize(p^) + FreeMem(p);

           没有可代替的函数,也不能少finalize(p^)这步操做,不然会有leak.

       b: record/object的指针类型,最好使用此对函数进行分配及释放。固然你也能够去自维护record/object里面的字段生存期。

       c: 若是调用system.Initialize/Finalize,出现提示:

           [Hint] Unit1.pas(43): Expression needs no Initialize/Finalize

           表示record/object里面的字段,没有包含string,interface,dync array,variant,record,array 

           即表示不须要调用Initialize或Finalize进行操做。

       d: 多说一句:每一个warn/hint都有其做用,请勿忽略,说不定小BUG就在其中,请关注它们或干掉它们。

 

二:GetMem/FreeMem

     GetMem/FreeMem是MM的分配与释放内存块函数,多说一些是与之相关的:此两函数,会由于分配或释放失败而抛出异常(exception)

     而MM对应的标准分配与释放函数是以返回值形态进行处理的,即失败了,只会返回空值(nil)或非0,而不是异常。

     也就是说Get/FreeMem是针对于MM的标准函数进行了异常封装。

     异常信息:

       GetMem fail => Out of memory.

       分配失败,通常只会是进程的可用内存分配完毕,一般在内存泄露的状况下才会发生。

       FreeMem fail => Invalid pointer operation

       两次FreeMem同地址,第二次就有这invalid pointer异常了。:)

 

三:GetMemory/FreeMemory

      Get/FreeMemory与GetMem/FreeMem基本相同,惟一不相同的是,它直接以MM的对应函数的返回值做为返回,而不进行异常处理。

      即:GetMem调用MM.GetMem返回为nil,则有异常,而GetMemory则直接返回nil,交给调用者处理

            FreeMem调用MM.FreeMem返回非0(错误释放),则异常,而FreeMemory则直接返回0或非0,给调用者处理。

      这点很是有用,在写程序时,能够减小异常,或者在Get/Free出现错误时,写句assert(...),让程序中断下来,检查并调试。

 

四:SysGetMem/SysFreeMem

      SysGetMem/SysFreeMem与GetMemory/FreeMemory基本相同,区别在于,它直接调用MM的实现函数,

      则不是通过MM的管理器指针再行跳转。

      即说:SysGet/SysFreeMem,它使用的是系统自带的MM分配释放函数,当第三方MM加入后,以上三对函数,

      都会由第三方MM接管,但SysGet/SysFreeMem它仍是调用的本系统自带的MM函数处理,与第三方MM无关。

 

五:其它

      其它还有些Delphi单元的分配释放函数,不过基本是从以上四对函数扩展出来,就不说明了

      固然也有从API扩展出来的分配+释放函数,则不在此列,它与D系统的MM扩展无关。

 

总结:

    New+Dispose与GetMem+FreeMem,是基于VCL异常机制保护的分配+释放函数。

    GetMemory+FreeMemory与SysGetMem+SysFreeMem是由调用者自行控制返回,来决定是否返回异常或错误处理。

   

完。

2014.10.19 by qsl

相关文章
相关标签/搜索