2009-08-23 28 views
8

GetMem允許您分配任意大小的緩衝區。在某處,內存管理器會保留大小信息,因爲當您將指針傳遞給FreeMem時,不需要告訴它緩衝區有多大。如何找到指針引用的內存大小?

該信息僅供內部使用,還是有任何方法檢索指針指向的緩衝區的大小?

+0

相關:http://stackoverflow.com/questions/969007/is-it-possible-to-get-the-size-of-the-type-that-a-pointer-points-to-in-delphi -7/http://stackoverflow.com/questions/232691/how-can-i-get-the-size-of-an-array-from-a-pointer-in-c – 2009-08-23 19:11:45

回答

8

這似乎是由的getmem()返回一個指針引用一個塊的大小必須從某處單獨分配,因爲freemem在()不需要您確定要釋放的內存大小 - 系統必須能夠確定,那爲什麼不是應用程序開發人員?但是,正如其他人所說的那樣,所涉及的存儲器管理的確切細節不是由系統本身定義的。Delphi一直有一個可替換的內存管理器體系結構,而爲兼容內存管理器定義的「接口」並不要求它們爲任意指針提供這些信息。

默認的內存管理器將以任何適合它的方式維護必要的信息,但其他一些內存管理器幾乎肯定會使用完全不同的,即使表面上相似的機制,所以即使您基於對一個內存管理器,如果你改變了內存管理器(或者如果你改變了你的內存管理器,比如修改了系統定義的內存管理器,你可能默認使用內存管理器,例如Delphi 2005和2006之間),那麼你的解決方案几乎肯定會中斷。

一般來說,對於RTL /內存管理器而言,應用程序應該已經知道分配的指針指向的內存塊有多大,假設應用程序需要它在第一位! :)

如果您的應用程序沒有分配指針,那麼您的應用程序的內存管理器絕對沒有辦法知道它引用的塊可能有多大。例如,它可能是一個指向某個較大塊的中間的指針 - 只有指針的源可能知道它與它所引用的內存之間的關係。

但是,如果你的應用程序確實需要維護這些信息關於它的自己指針,那麼它當然可以很容易地設計出一種方法用一個簡單的單類或函數庫來實現這一目標,通過它的getmem()/FreeMem()請求被路由,以維護每個當前分配指針的相關請求大小的記錄。當然,這樣的機制當然可以根據需要,完全可靠地獨立於所使用的任何內存管理器而容易地公開該信息。

這可以在面是唯一的選擇是否需要「準確」的記錄,爲給定的存儲器管理器實現比實際請求可以分配較大的內存塊用於數據的給定尺寸。我不知道是否有內存管理者確實會這樣做,但爲了效率,理論上可以這樣做。

0

該信息僅供內部使用,還是有任何方法檢索指針所指向的緩衝區的大小?

這兩個「替代品」是否相互矛盾?

僅供內部使用。

+0

我的意思是,是開發者隱藏的信息,因爲它僅供內部使用,還是有辦法得到它? – 2009-08-23 19:13:12

+0

什麼*我*意味着即使這些信息僅供內部使用,您仍然可能有辦法得到它。或者可能不。真實的說法是*這些信息僅供內部使用*。其他一切都無關緊要。 – 2009-08-23 19:38:44

0

在分配區域之前有一些信息用於存儲元信息。這意味着,每次您分配一塊內存時,都會分配一個更大的內存塊,並將首個字節用於元信息。返回的指針指向此元信息後面的塊。

我可以想象格式會隨着其他版本的內存管理器而改變,所以不要指望這一點。

0

該信息僅供內部使用。

請注意,內存管理器不需要將大小作爲返回內存的一部分進行存儲,許多內存管理器會將其存儲在內部表中,並使用作爲查找鍵給出的塊開始的內存地址在那張桌子裏。

5

這是內部使用,因爲它取決於所使用的MemoryManager。順便說一句,這就是爲什麼你需要使用來自同一個MemoryManager的GetMem/FreeMem對;沒有規範的方式知道如何保留內存。
在Delphi,如果你看FastMM4,可以看到的是,存儲器被在小型,中型或大型塊分配:
小塊在固定大小的塊的池(塊大小是在池中定義分配在塊型水平)

TSmallBlockType = packed record 
    {True = Block type is locked} 
    BlockTypeLocked: Boolean; 
    {Bitmap indicating which of the first 8 medium block groups contain blocks 
    of a suitable size for a block pool.} 
    AllowedGroupsForBlockPoolBitmap: byte; 
    {The block size for this block type} 
    BlockSize: Word; 

介質塊也被分配在池中,但是具有可變的大小

{Medium block layout: 
    Offset: -8 = Previous Block Size (only if the previous block is free) 
    Offset: -4 = This block size and flags 
    Offset: 0 = User data/Previous Free Block (if this block is free) 
    Offset: 4 = Next Free Block (if this block is free) 
    Offset: BlockSize - 8 = Size of this block (if this block is free) 
    Offset: BlockSize - 4 = Size of the next block and flags 

    {Get the block header} 
    LBlockHeader := PCardinal(Cardinal(APointer) - BlockHeaderSize)^; 
    {Get the medium block size} 
    LBlockSize := LBlockHeader and DropMediumAndLargeFlagsMask; 

個大塊與所需大小

TLargeBlockHeader = packed record 
    {Points to the previous and next large blocks. This circular linked 
    list is used to track memory leaks on program shutdown.} 
    PreviousLargeBlockHeader: PLargeBlockHeader; 
    NextLargeBlockHeader: PLargeBlockHeader; 
    {The user allocated size of the Large block} 
    UserAllocatedSize: Cardinal; 
    {The size of this block plus the flags} 
    BlockSizeAndFlags: Cardinal; 
    end; 
+0

我認爲ansistring依賴於前綴的大小。似乎沒有統一的方式來加載塊大小來做到這一點,這是如何工作的?現在分配中有大小嗎? – 2009-08-24 05:28:53

+1

AnsiString的前綴是* length *,但是這是因爲RTL在調用'GetMem'之前增加了額外的4個字節。 (另外4個用於引用計數,截至Delphi 2009,2個用於代碼頁,2個用於元素大小。)當您加長字符串時,RTL調用「ReallocMem」,它允許內存管理器選擇是否在原地膨脹分配或分配新的區塊(帶有新地址)。它永遠是那樣的; AnsiStrings不使用內存管理器的內部簿記。 – 2009-08-24 13:36:51