如何实现内存堆
Posted
技术标签:
【中文标题】如何实现内存堆【英文标题】:How to implement a memory heap 【发布时间】:2011-05-28 14:45:57 【问题描述】:不完全确定如何表达标题,但问题是:
我听说程序员会在程序开始时分配一大块连续内存,然后根据需要进行处理。这与每次需要内存时都简单地访问操作系统相反。 我听说这会更快,因为它可以避免不断向操作系统询问连续的内存块的成本。
我相信 JVM 就是这样做的,它维护自己的内存部分,然后从中分配对象。
我的问题是,如何实际实现这一点?
【问题讨论】:
“进入操作系统”是什么意思?堆完全在用户模式下实现,每次堆分配都不需要系统调用,除非需要分配更多页面。或者你有什么不同的想法? “我如何实现内存管理器”这个问题很好,但你必须确保你真的需要这个。如果你这样做是为了训练或只是为了好玩——好吧。如果您确定内存分配是程序中的瓶颈,则应首先考虑重新设计程序,以便分配更大的块。只有在你完成之后,你才应该使用自己的内存管理器。 【参考方案1】:你在程序开始时分配了一块足够大的内存来维持它的需要。然后你必须重写 new 和/或 malloc、delete 和/或 free 以从/向这个缓冲区返回内存。
在实现这种解决方案时,您需要编写自己的分配器(从块中获取源),并且您最终可能会使用多个分配器,这通常是您首先分配内存池的原因。
默认内存分配器是一个很好的全方位分配器,但并不是所有分配需求的最佳选择。例如,如果您知道要为特定大小分配大量对象,则可以定义一个分配器来分配固定大小的缓冲区并预分配多个缓冲区以提高效率。
【讨论】:
【参考方案2】:大多数 C 和 C++ 编译器已经提供了堆内存管理器作为标准库的一部分,因此您根本不需要做任何事情来避免每次请求都会影响操作系统。
如果您想提高性能,有许多改进的分配器,您可以简单地链接并使用它们。例如Hoard,在一个现已删除的答案中提到了哪些小麦(实际上非常好——小麦,你为什么要删除它?)。
如果您想编写自己的堆管理器作为学习练习,以下是它需要做的基本事情:
向操作系统请求一大块内存 保留空闲块的链接列表 当分配请求进来时: 在列表中搜索一个块,该块对于请求的大小足够大,另外还有一些存储在旁边的簿记变量。 为当前请求拆分足够大的块,将其余块放回空闲列表中 如果没有足够大的块,返回操作系统并请求另一个大块 当一个解除分配请求进来时 读取标题以找出大小 将新释放的块添加到空闲列表中 (可选)查看紧随其后的内存是否也列在空闲列表中,并将两个相邻块合并为一个更大的块(称为合并堆)【讨论】:
【参考方案3】:这是经典的分配器,也是最适合非多线程使用的分配器之一:
http://gee.cs.oswego.edu/dl/html/malloc.html
您可以从阅读其设计说明中学到很多东西。文章中malloc.c
的链接已经烂掉;现在可以在http://gee.cs.oswego.edu/pub/misc/malloc.c找到它。
话虽如此,除非您的程序具有非常不寻常的分配模式,否则编写自己的分配器或使用自定义分配器可能是一个非常糟糕的主意。尤其是如果您尝试替换系统 malloc
,您可能会面临来自不同库(或标准库函数)的各种错误和兼容性问题,这些错误和兼容性问题会链接到“malloc
的错误版本”。
如果您发现自己需要专门分配几个特定任务,则无需替换 malloc
即可完成。我建议查找 GNU obstack
和固定大小对象的对象池。这些涵盖了专门分配可能具有实际实用性的大多数情况。
【讨论】:
断章取义——您在 SO 上提供的参考资料太好了。我一直想知道如何将它们作为我的记忆来记住所有有限的东西:-(。【参考方案4】:-
是的,stdlib 堆和操作系统堆/虚拟内存都非常麻烦。
操作系统调用真的很慢,stdlib 更快,但仍然有一些“不必要的”
锁定和检查,并为分配的块增加了显着的开销
(即除了您分配的内存之外,还有一些内存用于管理)。
在许多情况下可以完全避免动态分配,
通过使用静态结构来代替。例如,有时定义 64k 会更好(更安全等)
unicode 文件名的静态缓冲区,而不是定义指针/std:string 和动态
分配它。
当程序必须分配大量相同结构的实例时,它的
更快地分配大内存块,然后将实例存储在那里
(按顺序或使用空闲节点的链表)- C++ 对此有一个“新位置”。
在许多情况下,当使用可变大小的对象时,可能大小的集合
实际上非常有限(例如 4+2*(1..256)),所以它可以使用
像 [3] 这样的几个池,而无需收集垃圾、填补空白等。
对于特定任务的自定义分配器来说,它通常比分配器快得多
来自标准库,甚至比速度优化但过于通用的实现还要快。
现代 CPU/操作系统支持“大页面”,这可以显着提高内存
显式处理大块时的访问速度 - 请参阅http://7-max.com/
【讨论】:
【参考方案5】:IBM developerWorks 有一篇关于内存管理的精彩文章,其中包含大量资源部分供进一步阅读:Inside memory management。
***也有一些很好的信息:C dynamic memory allocation、Memory management。
【讨论】:
以上是关于如何实现内存堆的主要内容,如果未能解决你的问题,请参考以下文章