程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> delphi.memory.分配及釋放---New/Dispose, GetMem/FreeMem及其它函數的區別與相同,---newgetmem

delphi.memory.分配及釋放---New/Dispose, GetMem/FreeMem及其它函數的區別與相同,---newgetmem

編輯:Delphi

delphi.memory.分配及釋放---New/Dispose, GetMem/FreeMem及其它函數的區別與相同,---newgetmem


我估摸著內存分配+釋放是個基礎函數,有些人可能沒注意此類函數或細究,但我覺得還是弄明白的好。

 

介紹下面內存函數前,先說一下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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved