码迷,mamicode.com
首页 > Windows程序 > 详细

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

时间:2015-07-29 21:09:39      阅读:1436      评论:0      收藏:0      [点我收藏+]

标签:

转载自:http://www.cnblogs.com/qiusl/p/4028437.html?utm_source=tuicool

 

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

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

TMemoryManger = record
GetMem: function(Size: Integer): Pointer;
FreeMem: function(P: Pointer): Integer;
ReallocMem: function(P: Pointer; Size: Integer): Pointer;
end;

var
MemoryManger: TMemoryManager = (
GetMem: SysGetMem;
FreeMem: SysFreeMem;
ReallocMem: SysReallocMem);

  以上时D7版本的MM函数数,其中变量MemoryMangeer我成为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、dync array字段,不会因为直接调用FreeMem而泄露(Leak)。

  总结是:

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

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

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

  没有课替代的函数,也不能少finalize(p^)这步操作,否则会有leak。

2) record/object 的指针类型,最好使用此对函数(New/Dispose)进行分配与释放。当然你也可以去自维护record/object里面的字段生存期。

3) 如果调用system.Initialize或Finalize,出现提示:

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

  表示record/object 里面的字段,没有包含string,interface,dync array,variant,record,array,也就表示不需要调用Initialize或 Finalize进行操作

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

 

GetMem/FreeMem               

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

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

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

  异常信息:

    GetMem fail =>Out of Memory:分配失败,一般只会是进程的可用内存分配完毕,通常在内存泄露的情况下才会发生。

    FreeMem fail=>Invalid pointer operation:两次FreeMem同地址,第二次就有这个invalid pointer异常了

 

GetMemory/FreeMemory            

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

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

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

  这点非常有用,在写程序的时候,可以减少异常,或者在Get/Fee出现错误时,写句assert(...),让程序中断下来,检查并调试。

 

SysGetMem/SysFreeMem           

  SysGetMem/SysFreeMem与GetMemory/FreeMemory基本相同,区别在于,它直接调用MM的实现函数,而不是经过MM的管理器指针再行跳转。

  即:SysGet/SysFreeMem,它使用的是系统自带的MM分配释放函数,当第三方MM加入后,以上三队函数都会由第三方MM接管,但SysGet/SysFreeMem它还是调用的本系统自带的MM函数处理,与第三方的MM无关。

 

其他                        

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

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

 

总结                        

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

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

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

标签:

原文地址:http://www.cnblogs.com/xumenger/p/4687284.html

(0)
(1)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!