繁体   English   中英

Win32 HeapCreate() initialSize 不支持大分配

[英]Win32 HeapCreate() initialSize doesn't support big allocations

我们在使用 HeapCreate()/HeapAlloc() 进行大分配(> 512K)时遇到问题

我们正在开发一个 C++ 服务器应用程序,在一些图像上同时执行一些“图像处理”操作。 它应该可以长时间工作而无需重新启动。

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

这意味着我们在开始时使用了所有必需的内存,并且内存总量不应增加(如果一切正常)。 我们的痛苦是分裂。 传入图像的大小可能从 400K 到 50M 不等,每个图像的处理都会导致相应的(与图像大小成比例)相对较大的 OPENCV 分配。 处理场景(和相关分配)各不相同,取决​​于图像的具体情况,分配/释放操作非常密集,然后一段时间后我们就会碎片化。 鉴于可以忽略不计的改进,开发了一些局部优化。 实际上我们在大约之后有内存不足/碎片相关的影响。 50000-70000 图像这是不太可接受的。 当前的解决方案是重启服务器,这远非理想。

解决问题的最初天真提议是:

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

简单的概念验证项目很快就得出了以下结论:

  • HeapCreate(),最初提交 250M,每次我从中调用 HeapAlloc() 时都会增加 10M! 很奇怪,不是吗?
  • 正如使用 HeapWalk() 所认识到的那样,提交的内存不是保留在一个连续的块中,而是保留为一个包含 500 多个 512K 块的列表。 所以它们都不适合我的 10M 请求和堆调用来处理未提交的内存

似乎 Win32 自定义堆仅针对小分配进行了优化,我无法找到一种方法来满足我的需要:( VirtualAlloc() 似乎是一个解决方案,但它是非常低级的 API,使用它意味着开发我的自己的内存管理系统,似乎是某种轮子改造。

我想相信存在某种标准方式,但我找不到它。 任何帮助或相关阅读资源将不胜感激

一些想法:

  1. 堆通常从较大的内存块管理小的子分配。 如果您需要大量分配,堆可能不是解决方案。 您可能必须自己动手并直接处理虚拟内存。

  2. 目前尚不清楚用于大分配的 HeapAlloc 是否实际上是从堆的保留内存中分配的。 MSDN 有点含糊,有时自相矛盾,但低碎片堆(LFH) 上的页面说大于 16 KB 的分配不使用 LFH。 这可能意味着堆会为您跟踪它,但真正满足来自 VirtualAlloc 调用而不是来自保留内存的大量分配。 如果是这种情况,使用堆可能只会让事情变得更糟。 (无论如何,无论是否启用 LFH,都值得一试。)

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

  4. 另一种方法是平铺,尽管这会极大地影响您的应用程序的架构。 这个想法是使用固定大小的图块而不是可变大小的图像。 根据图块大小,根据需要将图像切割成尽可能多的图块。 图块是独立处理的,输出图像是从图块重新组合而成的。 由于所有图块的大小相同,因此可以避免碎片化。 一些图像处理非常适合这一点,但其他类型则不然。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM