我们偶尔会遇到问题,即由于内存分配失败,我们长时间运行的服务器进程(在Windows Server 2003上运行)引发了异常.我们怀疑这些分配是由于内存碎片而失败的.
因此,我们一直在寻找一些可能对我们有帮助的替代内存分配机制,我希望有人可以告诉我最好的一个:
1)使用Windows 低碎片堆
2)jemalloc - 用于Firefox 3
3)Doug Lea的malloc
我们的服务器进程是使用跨平台的C++代码开发的,因此任何解决方案都可以理想地跨平台(do*nix操作系统会遭受这种类型的内存碎片吗?).
另外,我认为LFH现在是Windows Server 2008/Vista的默认内存分配机制吗?如果我们的客户只是升级他们的服务器操作系统,我当前的问题会"消失"吗?
首先,我同意其他提出资源泄漏的海报.你真的想先排除它.
希望您当前使用的堆管理器有一种方法可以转储堆中可用的实际总可用空间(跨所有空闲块)以及它被分割的块总数.如果平均空闲块大小与堆中的总可用空间相比相对较小,那么您确实存在碎片问题.或者,如果您可以转储最大空闲块的大小并将其与总可用空间进行比较,那么这将完成相同的任务.如果您遇到碎片,则相对于所有块中可用的总可用空间,最大的空闲块将很小.
为了清楚上述内容,在所有情况下,我们都在讨论堆中的空闲块,而不是堆中分配的块.在任何情况下,如果不满足上述条件,那么您确实存在某种泄漏情况.
因此,一旦排除了泄漏,您可以考虑使用更好的分配器.Doug Lea的malloc在问题中提出了一个非常好的通用应用程序分配器,并且在大多数情况下非常强大.换句话说,它经过时间测试,可以很好地适用于大多数应用程序.但是,没有算法适用于所有应用程序,并且任何管理算法方法都可以通过针对其设计的正确的语法条件来打破.
为什么你有碎片问题?- 碎片问题的来源是由应用程序的行为引起的,并且与同一内存领域中的大大不同的分配生存期有关.也就是说,一些对象被定期分配和释放,而其他类型的对象在同一堆中持续很长一段时间......想想更长寿命的对象是在竞技场的更大区域戳洞,从而防止已释放的相邻块的合并.
为了解决这类问题,你可以做的最好的事情是将堆逻辑地划分为生命周期更相似的子竞技场.实际上,您需要一个临时堆和一个持久堆或堆,它们对相似生命周期的事物进行分组.
其他一些人提出了另一种解决问题的方法,即尝试使分配大小更相似或相同,但这不太理想,因为它会产生一种称为内部碎片的不同类型的碎片 - 这实际上是你浪费的空间通过在块中分配比您需要的更多内存.
另外,使用像Doug Lea这样的好的堆分配器,使得块大小更相似是不必要的,因为分配器已经具有两个大小的分段方案的功能,这将使得完全没有必要人为地调整传递给malloc的分配大小( ) - 实际上,他的堆管理器会自动为您执行此操作,而不是应用程序可以进行调整.
我认为你错误地排除了过早的内存泄漏.即使是微小的内存泄漏也可能导致严重的内存碎片.
假设您的应用程序行为如下:
分配10MB
分配1个字节
空闲10MB
(oops,我们没有释放1个字节,但谁关心1个小字节)
这似乎是一个非常小的泄漏,在监视总分配的内存大小时,您几乎不会注意到它.但是这种泄漏最终会导致你的应用程序内存看起来像这样:
.
.
免费 - 10MB
.
.
[分配-1字节]
.
.
免费 - 10MB
.
.
[分配-1字节]
.
.
免费 - 10MB
.
.
这个泄漏将不会被注意到...直到你想要分配11MB
假设你的minidumps包含完整的内存信息,我建议使用DebugDiag来发现可能的泄漏.在生成的内存报告中,仔细检查分配计数(不是大小).
正如你的建议,Doug Lea的malloc可能运作良好.它是跨平台的,已用于运输代码.至少,应该很容易集成到您的代码中进行测试.
在固定内存环境中工作了很多年,这种情况肯定是一个问题,即使在非固定环境中也是如此.我们发现CRT分配器在性能(速度,浪费空间效率等)方面往往很糟糕.我坚信如果你在很长一段时间内都需要一个好的内存分配器,你应该自己编写(或者看看像dlmalloc这样的东西是否可行).诀窍是获得一些适用于您的分配模式的内容,这与内存管理效率几乎完全不同.
试试dlmalloc吧.我绝对赞不绝口.它也是相当可调的,因此您可以通过更改一些编译时选项来提高效率.
老实说,你不应该依赖于新的操作系统实现"离开"的东西.N年后的服务包,补丁或其他新操作系统可能会使问题变得更糟.同样,对于需要强大内存管理器的应用程序,请不要使用编译器可用的库存版本.找一个适合您情况的产品.从dlmalloc开始并调整它以查看是否可以获得最适合您情况的行为.