zoukankan      html  css  js  c++  java
  • delphi.memory.分配及释放---New/Dispose, GetMem/FreeMem及其它函数的区别与相同

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

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

     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处理。

     

    一:New/Dispose

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

         然后分配与释放是调用的是GetMem/FreeMem函数,与GetMem/FreeMem不同之处是:

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

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

         这一步很重要,因为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

  • 相关阅读:
    SP笔记:交叉实现七行并成一行
    HTML tag 学习
    操作哈希表
    Efficient bipedal robots based on passivedynamic walkers
    Pushing People Around
    ZEROMOMENT PONTTHIRTY FIVE YEARS OF ITS LIFE

    Active Learning for RealTime Motion Controllers
    Accelerometerbased User Interfaces for the Control of a Physically Simulated Character
    Dynamic Response for Motion Capture Animation
  • 原文地址:https://www.cnblogs.com/qiusl/p/4028437.html
Copyright © 2011-2022 走看看