我们在使用HeapCreate()/ HeapAlloc()进行大量分配时遇到问题(> 512K)
我们正在开发一个C ++服务器应用程序,执行一些图像处理'同时对几张图像进行操作。它应该可以长时间工作而无需重新启动。
我们的处理模型非常具体。 服务器启动,执行一些必要的分析以检测最大值。给定硬件配置的并发映像数,意味着稳定工作,具有最佳性能,快速达到最大负载,然后在大多数情况下以相同的高负载运行或多或少,具体取决于输入队列。
这意味着我们在开始时利用所有必需的内存,并且内存总量不应增长(如果一切正常)。 我们的痛苦是碎片化。输入图像的大小可以从400K变化到可能50M,并且每个的处理导致相应的(与图像大小成比例)相对大的OPENCV分配。处理方案(和相关的分配)各不相同,取决于图像细节,分配/免费操作是非常密集的,然后一段时间后我们得到碎片。由于改进可以忽略不计,因此开发了一些局部优化。 实际上我们在大约之后会出现内存/碎片相关的影响。 50000-70000图像是不可接受的。目前的解决方案是重新启动服务器,这远非理想。
解决问题的初步天真提议是:
简单的概念验证项目很快就找到了以下内容:
似乎Win32自定义堆仅针对小分配进行了优化,我无法找到一种方法来满足我的需求:( VirtualAlloc()似乎是一个解决方案,但它是非常低级的API,使用它意味着开发我自己的内存管理系统,似乎是某种轮子改造。
我想相信存在一些标准方式,我找不到它。 任何帮助或相关资源将非常感谢
答案 0 :(得分:0)
一些想法:
堆通常从较大的内存块管理小的子分配。如果您需要大量分配,则堆可能不是解决方案。您可能需要自己动手并直接处理虚拟内存。
目前尚不清楚大量分配的HeapAlloc是否实际是从堆的保留内存中分配的。 MSDN有点模糊,偶尔也会自相矛盾,但low-fragmentation heap(LFH)上的页面表示大于16 KB的分配不使用LFH。这可能意味着堆会为您跟踪它,但确实满足VirtualAlloc调用的大量分配,而不是来自保留的内存。如果是这样的话,使用堆可能只会让事情变得更糟。 (无论如何,使用和不启用LFH可能值得尝试。)
如果您的问题往往是碎片而不是实际的内存耗尽,那么您可能最好浪费一些内存以消除碎片。如果您的最大分配需要50 MB,那么您可能会考虑将所有分配大50 MB,即使图像要小得多。平均而言,您将分配较少的块(因此您无法同时处理多个图像),但如果分配的大小始终相同,您将永远不会得到碎片。这是否可接受的权衡取决于您的具体情况。你可以妥协并拥有一堆X大小的块来处理较小的块,如果它们更常见,只有一些大小为Y来处理尽可能大的块。
另一种方法是平铺,但这会极大地影响应用程序的架构。这个想法是使用固定大小的瓷砖而不是可变尺寸的图像。根据图块大小,根据需要将图像切割成多个图块。瓷砖是独立处理的,输出图像是从瓷砖中重新组装的。由于所有瓷砖尺寸相同,因此可以避免碎片。有些图像处理非常适合这种情况,但其他类型则不然。