动态数组内存分配策略
Dynamic Array Memory Allocation Strategies
我编写了一个 32 位程序,使用动态数组来存储具有未知计数的三角形列表。我目前的策略是估计大量的三角形,然后在创建所有三角形后 trim 列表。在某些情况下,我只会分配一次内存,而在其他情况下,我需要添加到分配中。
对于非常大的数据集,当我的应用程序内存使用量约为 1.2GB 时,我 运行 内存不足,并且由于分配步骤太大,我觉得我可能正在碎片化内存。
查看 FastMM(内存管理器),我看到了这些常量,这些常量建议其中之一作为递增的合适大小。
ChunkSize = 64 * 1024;
MaximumSmallBlockSize = 32752;
LargeBlockGranularity = 64 * 1024;
其中之一是否是增加数组大小的最佳大小?
最终这个程序会变成 64 位,但我们还没有完全准备好。
你真正的问题不是你 运行 内存不足,而是内存分配器无法找到足够大的连续地址块 space。您可以做的一些简单的事情包括:
- 在 64 位进程中执行代码。
- 添加
LARGEADDRESSAWARE
PE 标志,以便您的进程获得 4GB 地址 space 而不是 2GB。
除此之外,您可以做的最好的事情就是分配较小的块,这样就可以避免将大型数据结构存储在连续内存中的要求。以块为单位分配内存。因此,如果您需要 1GB 的内存,例如分配 64 个大小为 16MB 的块。您可以根据需要调整您使用的确切块大小。较大的块会产生更好的分配性能,但较小的块允许您使用更多地址 space.
将其包装在一个容器中,该容器向消费者呈现类似数组的接口,但在内部将内存存储在非连续块中。
据我所知,Delphi中的动态数组使用连续地址space(至少在虚拟内存地址space中)
由于您 运行 内存不足 1.2 gb,我想这就是内存管理器无法找到足够大的块连续内存以容纳更大数组的地方。
解决此限制的一种方法是将数组实现为大小为(比方说)200 MB 的较小数组的集合。在您达到内存上限之前,这应该会给您更多空间。
根据 1.2 gb 的值,我猜你的程序没有编译成 "large address aware"。您可以看到 here 如何像这样编译您的应用程序。
最后一个技巧是将数组数据实际保存在文件中。我将这个技巧用于我的一个应用程序,我需要加载几 GB 的图像以在网格中显示。我所做的是从生成的文件中创建一个具有属性 FILE_ATTRIBUTE_TEMPORARY 和 FILE_FLAG_DELETE_ON_CLOSE 以及 saved/loaded 图像的文件。来自 CreateFile 文档:
A file is being used for temporary storage. File systems avoid writing
data back to mass storage if sufficient cache memory is available,
because an application deletes a temporary file after a handle is
closed. In that case, the system can entirely avoid writing the data.
Otherwise, the data is written after the handle is closed.
由于它使用缓存内存,我相信它允许应用程序使用超过 32 位限制的内存,因为缓存由 OS 管理并且(据我所知)没有映射到内部进程的虚拟内存 space。进行此更改后,性能仍然相当不错。但我不能说性能是否仍然足以满足您的需求。
我编写了一个 32 位程序,使用动态数组来存储具有未知计数的三角形列表。我目前的策略是估计大量的三角形,然后在创建所有三角形后 trim 列表。在某些情况下,我只会分配一次内存,而在其他情况下,我需要添加到分配中。
对于非常大的数据集,当我的应用程序内存使用量约为 1.2GB 时,我 运行 内存不足,并且由于分配步骤太大,我觉得我可能正在碎片化内存。
查看 FastMM(内存管理器),我看到了这些常量,这些常量建议其中之一作为递增的合适大小。
ChunkSize = 64 * 1024;
MaximumSmallBlockSize = 32752;
LargeBlockGranularity = 64 * 1024;
其中之一是否是增加数组大小的最佳大小?
最终这个程序会变成 64 位,但我们还没有完全准备好。
你真正的问题不是你 运行 内存不足,而是内存分配器无法找到足够大的连续地址块 space。您可以做的一些简单的事情包括:
- 在 64 位进程中执行代码。
- 添加
LARGEADDRESSAWARE
PE 标志,以便您的进程获得 4GB 地址 space 而不是 2GB。
除此之外,您可以做的最好的事情就是分配较小的块,这样就可以避免将大型数据结构存储在连续内存中的要求。以块为单位分配内存。因此,如果您需要 1GB 的内存,例如分配 64 个大小为 16MB 的块。您可以根据需要调整您使用的确切块大小。较大的块会产生更好的分配性能,但较小的块允许您使用更多地址 space.
将其包装在一个容器中,该容器向消费者呈现类似数组的接口,但在内部将内存存储在非连续块中。
据我所知,Delphi中的动态数组使用连续地址space(至少在虚拟内存地址space中)
由于您 运行 内存不足 1.2 gb,我想这就是内存管理器无法找到足够大的块连续内存以容纳更大数组的地方。
解决此限制的一种方法是将数组实现为大小为(比方说)200 MB 的较小数组的集合。在您达到内存上限之前,这应该会给您更多空间。
根据 1.2 gb 的值,我猜你的程序没有编译成 "large address aware"。您可以看到 here 如何像这样编译您的应用程序。
最后一个技巧是将数组数据实际保存在文件中。我将这个技巧用于我的一个应用程序,我需要加载几 GB 的图像以在网格中显示。我所做的是从生成的文件中创建一个具有属性 FILE_ATTRIBUTE_TEMPORARY 和 FILE_FLAG_DELETE_ON_CLOSE 以及 saved/loaded 图像的文件。来自 CreateFile 文档:
A file is being used for temporary storage. File systems avoid writing data back to mass storage if sufficient cache memory is available, because an application deletes a temporary file after a handle is closed. In that case, the system can entirely avoid writing the data. Otherwise, the data is written after the handle is closed.
由于它使用缓存内存,我相信它允许应用程序使用超过 32 位限制的内存,因为缓存由 OS 管理并且(据我所知)没有映射到内部进程的虚拟内存 space。进行此更改后,性能仍然相当不错。但我不能说性能是否仍然足以满足您的需求。