堆碎片化可能会导致服务器应用程序在预计运行数月后突然开始出现故障,认为它已经耗尽了内存。
假设我已经尽力减少在我的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));
}
与此处相同的答案:如何检测和估计C++程序中的堆碎片?
编写适用于您的内存分配模式的自己的内存管理器。或者购买一个(例如smart-heap)。
由于碎片化取决于您的内存分配模式/释放模式,因此很难给出更好的答案。但是,您可以查看固定大小的分配器,或查看smart heap page的分配处理方式。此主题还有许多论文。例如,尝试www.memorymanagement.org
或者您可以查看FastMM4 - 这是开源的,但是使用Pascal / Delphi。
还有一些编程技巧。最值得注意的是:Object Pool。在这种情况下,由于对象被重用而不是释放,因此没有碎片化。但我认为固定大小分配器比对象池表现更好。以这种方式使用对象池只是“穷人版”的固定大小分配器。
与其基于时间或请求数量安排重启,你可以检查堆以查看当碎片化达到某个水平时最大连续内存块的大小低于一定水平 - 说到底,当你尝试分配大于堆中最大空闲连续空间大小的对象时,你将开始看到内存不足错误,而不是所有内存都已用完。
你可以使用VirtualQueryEx遍历堆并找到最大的自由连续区域。关于如何做到这一点的示例,请参见this article。
显而易见的解决方法是挖掘过去发明的旧方案。例如,使用不透明句柄来代替原始指针来处理可移动对象。这样可以使堆进行碎片整理。