设计和编码一个非碎片化的静态内存池
Posted
技术标签:
【中文标题】设计和编码一个非碎片化的静态内存池【英文标题】:Designing and coding a non-fragmentizing static memory pool 【发布时间】:2011-04-24 19:36:44 【问题描述】:我以前听说过这个词,我想知道如何设计和编写代码。 如果可用,我应该使用 STL 分配器吗? 如何在没有操作系统的设备上完成? 使用它和使用常规编译器实现的 malloc/new 之间的权衡是什么?
【问题讨论】:
【参考方案1】:我建议您在投入大量精力编写自己的内存分配器之前,应该知道您需要一个非分段内存分配器。 std 库提供的那个通常就足够了。
如果您需要,减少碎片的一般想法是一次获取大块内存并从池中分配,而不是要求操作系统在堆内零星地和高度变化的位置为您提供堆内存并穿插与许多其他大小不同的对象。由于专用内存分配器的作者对从池中分配的对象的大小以及这些分配如何发生有更多的了解,因此分配器可以比通用分配器(例如 STL 提供的分配器)更有效地使用内存。
您可以查看诸如Hoard 之类的内存分配器,它在减少内存碎片的同时,还可以通过提供减少争用的线程特定堆来提高性能。这可以帮助您的应用程序更线性地扩展,尤其是在多核平台上。
更多关于多线程分配器的信息可以在here找到。
【讨论】:
【参考方案2】:将尝试描述本质上是一个内存池 - 我只是在脑海中输入这个,自从我实现一个以来已经有一段时间了,如果有什么明显愚蠢的,这只是一个建议! :)
1。 为了减少碎片,您需要创建一个特定于您在其中分配的对象类型的内存池。本质上,然后您将每个分配的大小限制为您感兴趣的对象的大小。您可以实现一个模板类,该类具有动态分配的块列表(列表的原因是您可以增加空间量可用的)。每个动态分配的块本质上都是一个 T 数组。
然后,您将拥有一个“空闲”列表,它是一个单链表,其头部指向下一个可用块。然后分配只是简单地返回头部。您可以在块本身中覆盖链表,即每个“块”(表示 T 的对齐大小)本质上是 T 和链表中的一个节点的联合,分配时,它是 T,释放时,列表中的一个节点。 !!有明显的危险!!或者,您可以分配一个单独的(和受保护的块,这会增加更多开销)来保存块中的地址数组。
分配很简单,遍历块列表并从第一个可用的开始分配,释放也很简单,您需要做的额外检查是找到分配它的块,然后更新头指针。 (请注意,您需要使用placement new 或覆盖T 中的操作符new/delete - 有办法解决这个问题,google 是您的朋友)
我认为“静态”意味着 T 类型的所有对象都有一个单独的内存池。缺点是每个 T 都必须有一个单独的内存池。你可能很聪明,并且有一个对象来管理不同大小的池(例如,使用指向池对象的指针数组,其中索引是对象的大小)。
上一段的重点是准确概述这是多么复杂,就像上面 RC 所说,在你做之前确保你需要它 - 因为它可能会带来比必要的更多的痛苦!
2。 如果 STL 分配器满足您的需求,请使用它,它是由一些非常聪明的人设计的,他们知道自己在做什么 - 但是它适用于一般情况,如果您知道如何分配对象,则可以使上述执行速度更快。
3。 您需要能够以某种方式分配内存(硬件支持或某种 HAL - 无论如何) - 否则我不确定您的程序将如何工作?
4。 常规的 malloc/new 在幕后做了更多的事情(谷歌是你的朋友,我的答案已经是一篇文章!)我上面描述的简单分配器不是可重入的,当然你可以用互斥锁包装它提供一点掩护,即使那样,我也会冒险简单分配器的执行速度比正常的 malloc/free 快几个数量级。
但是,如果您处于优化的这个阶段 - 大概您已经用尽了优化算法和数据结构使用的可能性?
【讨论】:
关于第 3 条:所以仍然有一个“函数调用”以某种方式暴露给我,例如中断?至于你最后的话,我只是想提高我的低级技能,而且我的项目的答案是肯定的。 酷 - 你没有指定硬件。无论如何,只要你有能力“请求”一块内存,然后你可以在你的进程空间中寻址,你就很好.作为一项学习练习,绝对值得 - 对于生产应用程序 - 请格外小心! 因为我还没有选择硬件。不为该硬件提供 STL 的编译器供应商怎么办?有时会发生这种情况。就内存分配器而言,我该如何处理这些问题? 如果你没有STL分配器的访问权限,并且你还想实现自己的内存分配器(即系统自己的分配机制不足以满足你的需求),那么你不要确实有很多选择,但就像我说的,要格外小心......以上是关于设计和编码一个非碎片化的静态内存池的主要内容,如果未能解决你的问题,请参考以下文章