【问题标题】:Allocate a byte array and free it afterwards in delphi分配一个字节数组,然后在 delphi 中释放它
【发布时间】:2012-08-03 12:51:06
【问题描述】:

我想用一个字节数组分配空间(动态大小)并获得一个指向“空间区域”的指针,如果我不再需要它,以后再释放它。

我知道 VirtualAlloc、VirutalAllocEx 和 LocalAlloc。 哪个最好,之后如何释放内存?

感谢您的帮助。

【问题讨论】:

  • 你能解释一下GetMem有什么问题吗?
  • 从未想过getmem。对此感到抱歉。

标签: delphi winapi memory-management delphi-7


【解决方案1】:

我认为使用 winapi 代替本机 Pascal 函数不是一个好主意。

你可以简单地定义一个字节数组为

var yourarray: array of byte;

那么就可以分配了

setlength(yourarray, yoursize);

并被释放

setlength(yourarray, 0);

这样的数组是引用计数的,您可以以yourarray[byteid] 访问单个字节

或者如果你真的想要指针,你可以使用:

var p: pointer;

GetMem(p, yoursize);

FreeMem(p);

【讨论】:

  • 这行得通。但我忘了提到我需要指针/空间用于全球目的。如果一个函数,过程离开/返回,堆栈被刷新?!
  • @BenjaminWeiss 动态数组和 GetMem/FreeMem 都在堆上分配,而不是在堆栈上,因此除非它们超出范围(对于动态数组)或显式释放(指针),否则它们都是可用的。
【解决方案2】:

您最好使用GetMem/FreeMem 或动态数组,或RawByteString。请注意,GetMem/FreeMem、动态数组或RawByteString 使用 heap,而不是 stack 进行分配。

没有兴趣使用VirtualAlloc/VirtualFree 代替GetMem/FreeMem。对于大块,内存管理器(实现堆)将调用VirtualAlloc/VirtualFree API,但对于较小的块,它将更加优化以依赖堆。

由于VirtualAlloc/VirtualFree 是当前进程的本地,使用它的唯一兴趣是如果您想创建一些能够执行代码的内存块,例如用于通过 VirtualAllocEx/VirtualFreeEx API 创建一些类或接口的存根包装器(但我怀疑这是您的需要)。

如果您想为所有进程/程序使用一些全局内存,您可以使用GlobalAlloc/GlobalFree API 调用。

【讨论】:

    【解决方案3】:

    VirtualAlloc 是一个页面分配函数。它是用于分配内存的低级用户空间代码函数。但是你必须明白,从 VirtualAlloc 返回的内存是对齐到页面大小的倍数。

    在 32 位 Windows 上,页面大小通常为 4096 字节。在其他系统上它可能更大。

    因此,当您需要整页内存时,这使得 VirtualAlloc 很有用。 VirtualAlloc 可以分配大的“页面范围”。这些页面是虚拟的,因此实际上是到底层系统 RAM 的映射,并且有一半的时间被换出到交换文件,这就是为什么它被称为 VirtualAlloc,强调虚拟。

    使用 VirtualAlloc 和 VirtualAllocEx 你也可以只保留一些内存页。保留页面是在您确定它们将被使用之前保持在保留状态的范围,此时您可以提交页面,此时将分配/提交页面所需的基础资源。

    使用 VirtualFree 释放您使用 VirtualAlloc 分配或保留的页面。

    VirtualAlloc 和 LocalAlloc 之间的区别在于 LocalAlloc 从堆中分配,而堆是一种从更大的保留页面块分配内存块的机制。在内部,堆使用 VirtualAlloc 分配大部分内存,然后将这些页面分成更小的块,您可以将这些块视为从 malloc、getmem 和 LocalAlloc 等函数返回的缓冲区。

    LocalAlloc 可以看作是 Windows 内置版本的 malloc 或 getmem。对 LocalAlloc 的调用类似于在 C++ 中调用 malloc 或在 Delphi 中调用 getmem。事实上,您可以在 Delphi 中覆盖 GetMem 并使用 LocalAlloc,您的 DElphi 应用程序可能会运行相同。

    调用 LocalFree 以释放一些使用 LocalAlloc 分配的内存。在内部,这会将内存块标记为可供下一个调用者使用。

    所以现在决定时主要考虑的是开销。如果您需要经常分配,那么您应该使用 LocalAlloc 或 getmem,因为提交和保留虚拟页面是一个更耗时的过程。

    换句话说,请使用 getmem 或 LocalAlloc,除非您有非常特殊的理由不这样做。

    在我使用 Delphi 5 与 C++ 编译器的所有测试中,Delphi 5 getmem 更快,尽管那是五年前的事了。从那时起,像hoard 这样的分配器就可以使用,它可能会更快。但是当变量如此之多时,很难说哪个更快。

    但可以肯定的是,LocalAlloc、malloc 和 getmem 等所有堆函数应该比使用 VirtualAlloc 分配和释放快得多,VirtualAlloc 通常用于在内部为 LocalAlloc 和 getmem 等堆函数保留内存。

    对于 Pascal 程序,首选 getmem 或 SetLength,因为它更便于移植。或者您可以将自己的包装函数写入 LocalAlloc 或任何 OS 堆函数。

    【讨论】:

      【解决方案4】:

      您列出的函数是 WinAPI 函数,它们是平台相关的。显然,您应该使用与分配相同的 API 的函数来解除分配。

      如果您想使用 Delphi 内存管理器,那么 GetMemory 和 FreeMemory 是显而易见的选择,但是如果您需要将指针与系统页面大小对齐(这是某些低级库的要求),或者您打算使用大缓冲区,那么 Windows API 虚拟内存函数 VirtualAlloc 和 VirtualFree 是你最好的朋友。

      【讨论】:

      • 谢谢。 VirtualFree 也是我一直在寻找的。​​span>
      • 使用GetMem/FreeMem,没有GetMemory/FreeMemory功能。而对于较大的块,GetMem 会调用 VirtualAlloc: 所以这里直接调用 VirtualAlloc/VirtualFree 没有任何好处。只会增加混乱。
      • @ArnaudBouchez 您所说的对于默认内存管理器来说是正确的。VirtualAlloc 的好处是您可以确保页面与页面大小对齐,至于 GetMem 行为,您可以'不知道缓冲区大小,因为可以在 Delphi 中的不同内存管理器之间切换,并且它们可以使用其他分配策略。
      • @BorisTreukhov 但是OP没有要求对齐内存,只是为了分配内存缓冲区。对齐 GetMem 返回的缓冲区非常容易(例如,多分配 15 个字节并对齐最近的 16 个字节边界),或者通过设置 Align16Bytes 编译选项将 FastMM4 设置为仅服务对齐的块。
      猜你喜欢
      • 1970-01-01
      • 2021-06-11
      • 2011-10-07
      • 1970-01-01
      • 1970-01-01
      • 2016-02-13
      • 2010-11-27
      • 2013-08-17
      • 1970-01-01
      相关资源
      最近更新 更多