Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 动态阵列内存分配策略_Delphi - Fatal编程技术网

Delphi 动态阵列内存分配策略

Delphi 动态阵列内存分配策略,delphi,Delphi,我已经编写了一个32位的程序,使用动态数组来存储未知计数的三角形列表。我目前的策略是估计大量三角形,然后在创建所有三角形时修剪列表。在某些情况下,我只分配一次内存,而在其他情况下,我需要添加到分配中 对于一个非常大的数据集,当我的应用程序内存使用量约为1.2GB时,我的内存将耗尽,而且由于分配步骤太大,我感觉可能是内存碎片 看一下FastMM(内存管理器),我看到了这些常量,这表明其中一个常量是一个很好的增量 ChunkSize = 64 * 1024; MaximumSmallBlockSiz

我已经编写了一个32位的程序,使用动态数组来存储未知计数的三角形列表。我目前的策略是估计大量三角形,然后在创建所有三角形时修剪列表。在某些情况下,我只分配一次内存,而在其他情况下,我需要添加到分配中

对于一个非常大的数据集,当我的应用程序内存使用量约为1.2GB时,我的内存将耗尽,而且由于分配步骤太大,我感觉可能是内存碎片

看一下FastMM(内存管理器),我看到了这些常量,这表明其中一个常量是一个很好的增量

ChunkSize = 64 * 1024;
MaximumSmallBlockSize = 32752;
LargeBlockGranularity = 64 * 1024;
其中之一是增加阵列大小的最佳大小吗


最终这个程序将变成64位,但我们还没有完全准备好进行这一步。

您真正的问题不是内存不足,而是内存分配器找不到足够大的连续地址空间块。您可以做一些简单的事情来提供帮助,包括:

  • 在64位进程中执行代码
  • 添加
    largeaddressware
    PE标志,以便您的进程获得4GB的地址空间,而不是2GB的地址空间
  • 除此之外,您所能做的最好的事情就是分配更小的块,以避免在连续内存中存储大型数据结构的要求。按块分配内存。因此,如果您需要1GB内存,例如,分配64个16MB大小的块。您使用的确切块大小可以根据您的需要进行调整。块越大,分配性能越好,但块越小,使用的地址空间就越多


    将其封装在一个容器中,该容器向使用者提供类似数组的接口,但在内部将内存存储在非连续块中。

    据我所知,Delphi中的动态数组使用连续地址空间(至少在虚拟内存地址空间中)

    由于1.2GB的内存不足,我想这就是内存管理器找不到足够大的块连续内存来容纳更大数组的地方

    解决此限制的一种方法是将阵列实现为(比如)200 mb大小的较小阵列的集合。在你达到记忆上限之前,这会给你更多的空间

    从1.2GB的值来看,我猜您的程序没有编译成“大地址感知”。您可以看到如何像这样编译应用程序

    最后一个技巧是将数组数据实际保存到文件中。我在我的一个应用程序中使用了这个技巧,我需要加载几GB的图像以显示在网格中。我所做的是创建一个属性为file_attribute_TEMPORARY和file_FLAG_DELETE_ON_CLOSE的文件,并从结果文件中保存/加载图像。从CreateFile文档:

    文件正被用于临时存储。文件系统避免写入 如果有足够的缓存可用,则将数据返回到大容量存储器, 因为应用程序在删除句柄后删除临时文件 关闭在这种情况下,系统完全可以避免写入数据。 否则,数据将在句柄关闭后写入


    由于它使用了缓存,我相信它允许应用程序使用超过32位限制的内存,因为缓存由操作系统管理,并且(据我所知)没有映射到进程的虚拟内存空间中。做了这个改动后,性能还是不错的。但我不能说性能是否仍能满足您的需要。

    忘了补充一点,分配较小的块可能更有效,但会影响性能。最佳内存分配是准确分配一次所需的内存量。这需要你事先知道正确的尺寸。真的没有办法知道吗?@RobKennedy只有当你忽略地址空间的问题时,这才是真的。在32位进程中,在分配大型对象时,在内存耗尽之前,地址空间就用完了。解决方案是分配较小的对象,但其中很多都是这样。我的测试分配较小,这使我能够处理更多的内存,但我仍然不足。我忘记了LARGEADDRESSWAWARE标志,并将添加该标志,但使用该标志是否有任何折衷?对于大于2GB的地址,您可能会在库代码中遇到错误。例如,Vista上的GetCursorPos无法处理此类地址。直截了当地说,假设你想避开磁盘,那么你所有可行的选择都可以在我的答案中找到。也就是说,内存映射文件可以帮助您访问64位磁盘缓存。你应该停止回避这个问题,制作一个64位的应用程序。切换到64位是正确的,但这是一个非常大的程序的一部分,需要的不仅仅是重新编译。将索引存储到共享顶点或线段的更高效的存储结构将有所帮助,但需要更长的时间来构建。谢谢你的帮助。我们考虑过在磁盘上存储,但性能会受到影响。只有少数客户使用的数据集太大,导致问题,所以这样做没有意义。设置较大的地址空间似乎可以解决目前的问题。使用FILE_ATTRIBUTE_TEMPORARY,如果有足够的系统内存可用,数据可能永久保留在内存中,在这种情况下,性能几乎不会受到影响。这和实际使用内存没什么区别。并不是因为您保留了“内存”,所以数据实际上会驻留在RAM中。不过,我承认现代系统通常有足够的RAM来避免使用交换文件。谢谢,我错过了。现在我很想测试缓存的性能。执行了一个简单的测试,缓存文件的速度要慢得多。对于1000000条记录,文件长度为3000ms,阵列长度为60ms。这仍然是一个很好的技巧。@Mitch我认为如果你使用一个内存映射文件,并且你做的每件事都很好,那么性能应该会很好