如何找到指针引用的内存大小?

时间:2009-08-23 18:55:34

标签: delphi memory-management pointers

GetMem允许您分配任意大小的缓冲区。在某处,大小信息由内存管理器保留,因为当您将指针传递给FreeMem时,不需要告诉它缓冲区有多大。

该信息仅供内部使用,或者有没有办法检索指针指向的缓冲区大小?

5 个答案:

答案 0 :(得分:8)

似乎 GetMem()返回的指针引用的块的大小必须可以从某个地方获得,因为 FreeMem()不需要你确定要释放的内存大小 - 系统必须能够确定,那么为什么不是应用程序开发人员呢?

但是,正如其他人所说,所涉及的内存管理的确切细节并非由系统本身定义.... Delphi一直有可更换的内存管理器架构,并且为兼容的内存管理器定义了“接口”不要求他们为任意指针提供此信息。

默认的内存管理器将以任何适合它的方式维护必要的信息,但是其他一些内存管理器几乎肯定会使用完全不同的,如果表面上相似的机制,所以即使你基于对一个人的熟悉知识来破解解决方案内存管理器,如果你改变内存管理器(或者如果你改变它,例如通过系统定义的更改,你可能默认使用的内存管理器,例如在Delphi 2005和2006之间发生),那么你的解决方案几乎肯定会破裂。

一般来说,RTL /内存管理器的一个不合理的假设是,应用程序应该已经知道 GetMem()分配的指针指向的内存有多大,该应用程序首先要求它! :)

如果您的应用程序没有分配指针,那么您的应用程序的内存管理器绝对无法知道它引用的块有多大。例如,它可能是指向某个较大块的 middle 的指针 - 只有指针的源可能知道它与它引用的内存的关系!

但是,如果您的应用程序确实需要维护有关它的自己的指针的信息,那么它当然可以通过简单的单例类或函数库轻松设计实现此目的的方法。 strong> GetMem() / FreeMem()请求被路由,以维护每个当前分配的指针的相关请求大小的记录。这样的机制当然可以根据需要轻松地公开这些信息,完全可靠,独立于正在使用的内存管理器。

如果需要“准确的”记录,这可能是唯一的选择,因为给定的内存管理器实现可能会为给定大小的数据分配比实际请求更大的内存块。我不知道是否有任何内存管理器确实这样做了,但为了提高效率,它可以在理论上这样做。

答案 1 :(得分: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;

答案 2 :(得分:0)

  

该信息仅供内部使用,或者有没有办法检索指针指向的缓冲区大小?

这两个“替代品”是否相互矛盾?

仅供内部使用。

答案 3 :(得分:0)

在分配区域之前存在一些信息来存储元信息。这意味着,每次分配一块内存时,都会分配一个更大的部分,并将第一个字节用于元信息。返回的指针指向此元信息后面的块。

我可以想象用其他版本的内存管理器改变了格式,所以不要指望它。

答案 4 :(得分:0)

该信息仅供内部使用。

请注意,内存管理器不需要将大小存储为返回的内存的一部分,许多内存管理器会将其存储在内部表中,并使用作为查找键发出的块的开头的内存地址。那张桌子。