对C ++堆分配器进行碎片整理& STL

时间:2009-09-20 12:14:11

标签: c++ memory-management heap defragmentation heap-fragmentation

我正在寻找一个自我整理内存管理器,其中一个简单的递增堆分配器与一个简单的压缩碎片整理程序结合使用。

粗略的方案是从最低内存地址开始向上分配块,并保持从最高内存地址开始向下工作的簿记信息。

内存管理器会传回智能指针 - 对于簿记结构来说,boost的intrusive_ptr似乎是最明显的,它本身会指向实际的内存块,从而提供一个间接级别,以便可以轻松地移动块。

碎片整理程序会从“生成”书签开始压缩堆,以加快进程,并且一次只对固定数量的内存进行碎片整理。对块本身的原始指针在下一次碎片整理通过之前是有效的,因此可以自由传递,直到这样的时间改善性能。

具体应用是控制台游戏编程,因此在每个帧的开头或结尾都可以相对安全地完成碎片整理传递。

所以我的问题是,任何人都使用这种分配方案与STL结合,它会让STL分开,因为我怀疑。我可以看到std :: list< intrusive_ptr>在intrusive_ptr级别工作但是stl列表节点本身的分配如何覆盖下一个/ prev指针是intrusive_ptr本身,或者我只需要一个标准的堆分配器和这个更动态的一个。

5 个答案:

答案 0 :(得分:5)

如果你要在内存中移动物体,那么你就无法完全做到这一点。您只能使用知道可能被移动的对象执行此操作。您还需要一个锁定机制。在对象上调用函数时,无法移动它。

原因是整个C ++模型依赖于位于内存中固定点的对象,因此如果一个线程在一个对象上调用一个方法,那么该线程被暂停并且对象被移动,当线程恢复时,灾难就会发生。

任何持有原始内存指针的对象都可以移动(包括它自己的子对象),但不会有效。

这样的内存管理方案可能有用,但你必须非常小心。您需要严格执行句柄和handle->指针锁定语义。

对于STL容器,您可以自定义分配器,但仍需要返回固定的原始内存指针。您无法返回可能移动的地址。因此,如果您正在使用STL容器,它们必须是句柄的容器,并且节点本身将是普通的动态分配内存。您可能会发现在句柄间接方面的开销太大,并且在句柄集合的碎片方面仍然存在问题,而不是使用STL获得的。

使用直接了解句柄的容器可能是前进的唯一方法,即使这样,与使用内存中修复的传统对象的C ++应用程序相比,仍然可能存在很多开销。

答案 1 :(得分:0)

使用裸指针实现STL容器。

您可以在实例化时指定自定义分配器(因此它们使用分配器初始化它们的指针),但是(因为分配的值存储在裸指针中)您不知道这些指针在哪里,因此您以后不能改变它们。

相反,您可以考虑自己实现STL的一个子集:然后可以使用托管指针实现您的STL容器版本。

答案 2 :(得分:0)

另一种众所周知的技术是buddy system。你应该看看它以获得额外的灵感。

答案 3 :(得分:0)

如果这是用于控制台游戏编程,则在运行时禁止无范围的动态内存分配要容易得多。在启动时,但这有点难以实现。

答案 4 :(得分:0)

我对此的看法是,如果必须害怕碎片,那就意味着你正在玩弄你记忆中很大一部分的数据碎片,而仅靠这种美德,你就不能拥有很多碎片。你知道这些会是什么吗?也许最好是降低一个级别并做出更具体的决策,从而减少对其他代码和应用程​​序的一般性能的影响?

列表是放入碎片整理内存管理器的一个非常糟糕的例子,因为它是一堆小块,就像大多数其他STL数据结构一样。如果你这样做,它会有各种明显的不良影响 - 包括你的碎片整理程序的性能下降,以及间接成本等。唯一有意义的结构IMO是有名的 - 数组,双端队列,哈希表的主要部分那些东西,只有超过一定的尺寸,并且只有在它们不再被重新调整大小之后。这些事情再次呼吁特定的解决方案,而不是通用的解决方案。

回顾一下结果如何。