堆碎片可能会导致预计连续运行数月的服务器应用程序突然开始出现故障,认为它内存不足。
假设我已尽最大努力将 VC++ 服务器应用程序中的运行时堆碎片最小化,但它仍然会累积并导致问题。例如,我可以每月或每处理 50 万个请求自动重新启动应用程序 - 安全地停止它并安全地重新启动一个新堆。我还能做些什么来解决堆碎片问题?
堆碎片可能会导致预计连续运行数月的服务器应用程序突然开始出现故障,认为它内存不足。
假设我已尽最大努力将 VC++ 服务器应用程序中的运行时堆碎片最小化,但它仍然会累积并导致问题。例如,我可以每月或每处理 50 万个请求自动重新启动应用程序 - 安全地停止它并安全地重新启动一个新堆。我还能做些什么来解决堆碎片问题?
一个好的起点是启用低碎片堆并检查它仍然碎片的天气。
HANDLE heaps[1025];
DWORD nheaps = GetProcessHeaps((sizeof(heaps) / sizeof(HANDLE)) - 1, heaps);
for (DWORD i = 0; i < nheaps; ++i) {
ULONG enableLFH = 2;
HeapSetInformation(heaps[i], HeapCompatibilityInformation, &enableLFH, sizeof(enableLFH));
}
这个新引入的内存管理器在 Vista/Server 2008 上默认开启......因此,如果您确定在较新的服务器操作系统上世界更好,这可能就是原因。
低碎片堆是随 Windows 2000 的服务包引入的,但在 Windows Vista 之前必须主动启用。
有一个工具vmmap可以轻松地概述内存,并在发生碎片时提供一个很好的概述。
与此处相同的答案:如何在我的 C++ 程序中检测和估计堆碎片?
编写适合您的内存分配模式的自己的内存管理器。或者买一个(例如智能堆)。
由于碎片取决于您的内存分配模式/释放模式,因此很难给出更好的答案。但是您可以查看固定大小的分配器或查看智能堆页面它们如何处理分配。也有很多关于这个主题的论文。尝试例如www.memorymanagement.org
或者你可以看看FastMM4——它是开源的,但是在 Pascal/Delphi 中
还有一些编程技术。最值得注意的是:对象池。在这种情况下,没有碎片,因为对象被重复使用而不是被释放。但我认为固定大小的分配器比对象池执行得更好。以这种方式使用的对象池只是一个“可怜的”固定大小分配器。
与其根据时间或请求数量安排重新启动,不如检查堆以查看碎片何时达到最大连续内存块低于某个级别时的级别 - 毕竟 - 你会开始看到内存错误不是在所有内存都用完时而是当您尝试分配大于堆中最大可用连续空间大小的对象时。
您可以使用VirtualQueryEx遍历您的堆并找到最大的空闲连续区域。有关如何执行此操作的示例,请参阅本文。
显而易见的解决方法是挖掘过去发明的旧解决方案。例如,可移动对象的不透明句柄而不是原始指针。这允许您对堆进行碎片整理。