我估摸着內存分配+釋放是個基礎函數,有些人可能沒注意此類函數或細究,但我以爲仍是弄明白的好。函數
介紹下面內存函數前,先說一下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