的Win32 HeapCreate()INITIALSIZE不支持大的分配

问题描述:

我们必须用HeapCreate()/ HeapAlloc()的大分配(> 512K)的Win32 HeapCreate()INITIALSIZE不支持大的分配

我们正在制定执行一些“图像的C++服务器应用程序的问题在几张图片上同时处理操作。它应该长时间工作而不重新启动。

我们的处理模型非常具体。 服务器启动,执行一些所需的分析以检测最大值。给定硬件配置的并发映像数量,意味着以最佳性能稳定工作,快速达到最大负载,然后根据输入队列在大部分时间以相同的高负载工作或多或少。

这意味着我们在开始时使用所有需要的内存,并且不应该增加内存总量(如果一切正常)。 我们的痛苦是分裂。传入图像的大小可能从400K到50M不等,每个处理都会导致相应的(与图像大小成比例的)相对较大的OPENCV分配。处理场景(和相关的分配)有所不同,取决于图像细节,alloc/free操作非常密集,然后在一段时间后我们会出现碎片。一些本地优化开发得到微不足道的改善。 事实上,我们在大约一年后出现了内存不足/碎片相关的影响。 50000-70000图像,这是不太可以接受的。目前的解决方案是重启服务器,这远非理想。

初始天真的建议来解决问题是:

  • 我们有自己的自定义堆最初提交整个所需的内存。
  • 所有必需的'大'OPENCV分配(只有那些)重定向到这个堆
  • 目前,碎片到了,我们停止新的输入并完成所有正在运行的作业。
  • 这意味着所有与图像相关的分配都被释放。
  • 检查堆并根据需要清理它(例如,由于内存泄漏)
  • 现在,我们有完全空的堆,可以从头开始。再次打开输入。

证明简单的概念迅速工程想通了以下内容:

  • HeapCreate(),提交初步250M,每一个我称之为HeapAlloc()从它时间一长由10M!奇怪,不是吗?
  • 正如使用HeapWalk()所承认的那样,提交的内存不是保留在一个连续的块中,而是保留在每个512K以上的500个块中。所以,他们都不是适合我的10M的要求和堆调用来处理未提交的内存

看来Win32的自定义堆为小分配唯一的优化,我无法找到一种方法,用它为我的需要:(VirtualDlloc()似乎是一个解决方案,但它是非常低级的API,并且使用它意味着我自己的内存管理系统的开发,似乎是某种*重新创建。

我想相信一些标准的方式存在和我无法找到它。 任何帮助或相关资源,读取将非常感激

+0

对不起初始格式。这是一个技术问题。 – vadimus

+0

这个问题今天完全无法解决。重建程序到目标x64。 –

+0

@HansPassant:重新定位到64位模型可能会简单地推迟问题而不是解决问题。如果一个程序存在一个有害的碎片问题,并且它必须无限期地运行,它最终会耗尽虚拟地址空间,并且可能会耗尽可用的存储空间(如果碎片非常糟糕以致页面无法被释放)。即使延期时间很长,表现可能会受到流失的影响。 –

几个想法:

  1. 堆一般管理从较大的内存块小的再次分配。如果您需要大量分配,堆可能不是解决方案。您可能必须自行推出并直接处理虚拟内存。

  2. 目前还不清楚HeapAlloc的大分配是否从堆的保留内存实际分配。 MSDN有点模糊,有时会自相矛盾,但low-fragmentation heap(LFH)上的页面指出,大于16 KB的分配不使用LFH。这可能意味着堆为你追踪它,但确实满足来自VirtualAlloc调用的大分配,而不是来自保留内存。如果是这样的话,使用堆可能会让事情变得更糟。 (无论如何,这可能值得尝试使用和不使用LFH。)

  3. 如果你的问题往往是碎片化而不是实际的内存耗尽,那么你最好不要浪费一些内存来消除碎片。如果您的最大分配需要50 MB,那么即使图像明显更小,您也可以考虑将所有分配设置为50 MB。平均而言,您分配的块数较少(因此您无法一次处理多少图像),但如果分配的大小始终相同,则永远不会分割。这是否是可以接受的取舍取决于你的情况的细节。你可以妥协,并有一堆X大小的块来处理较小的块,如果它们更常见,并且只有几个大小为Y的块来处理尽可能大的块。

  4. 另一种方法是平铺,尽管这会大大影响您的应用程序的架构。这个想法是使用固定大小的图块而不是可变大小的图像。根据瓷砖尺寸将图像裁切成所需的瓷砖。瓷砖被独立处理,并且输出图像从瓷砖重新组装。由于所有图块的大小相同,因此可避免碎片。一些图像处理非常适合这种情况,但其他类型则不适用。

+0

谢谢,瓷砖是一个非常好的主意。不幸的是,我们必须分析一个“完整的”文档区域,至少在第一阶段。一般来说,50M是800M大块的一个小分配。这将是以这种方式配置堆的理想解决方案。是的,似乎我们必须处理VirtualAlloc()。我只希望有一些标准或已知的实现存在针对大分配的堆(基于VirtualAlloc()) – vadimus

+0

您可以在平铺的顶部构建一个抽象,以便从代码的角度来看,它是只是一个大的图像,但该表示被划分成相同大小的图块。 –