如何实现内存堆。

24

我不是很确定如何措辞标题,但问题是:

我听说过程序员在程序开始时分配一大段连续的内存,然后根据需要分配它。这与每次需要内存时都向操作系统请求不同。

我听说这样做会更快,因为它可以避免不断向操作系统请求连续的内存块所带来的开销。

我相信JVM正是这样做的,它维护自己的内存部分,然后从中分配对象。

我的问题是,如何实现这个方法?


“去操作系统”是什么意思?堆完全在用户模式下实现,除非需要分配更多页面,否则不需要每次堆分配都进行系统调用。或者你想到了其他的东西吗? - wj32
2
“如何实现内存管理器”这个问题很好,但你必须确保你真的需要它。如果你是为了训练或者只是为了好玩而做 - 没问题。如果你确定内存分配是程序中的瓶颈,你应该首先考虑重新设计程序,使其分配更大的块。只有在完成这些工作之后,你才应该去使用自己的内存管理器。 - sharptooth
5个回答

23

大多数C和C++编译器已经作为标准库的一部分提供了堆内存管理器,因此您无需采取任何措施来避免每个请求都打到操作系统。

如果要提高性能,有许多改进的分配器可以使用,您只需链接即可。例如,Hoard是一个不错的选择,wheaties在一个已删除的答案中提到过它。

如果想编写自己的堆管理器作为学习练习,需要做以下基本事情:

  • 向操作系统请求一块大的内存块
  • 保持空闲块的链表
  • 当分配请求到来时:
    • 在列表中查找足够容纳请求大小加上一些存储在旁边的书记变量的块。
    • 从块中分离出足够大的块以满足当前请求,并将其余部分放回空闲列表。
    • 如果没有足够的块,请返回操作系统并请求另一个大的块。
  • 当释放请求到来时:
    • 读取头文件以查找大小
    • 将新释放的块添加到空闲列表中
    • 可选地,查看紧随其后的内存是否也列在空闲列表中,并将相邻的两个块合并成一个更大的块(称为堆合并)

7
你需要在程序开始时分配一块足够大的内存空间来满足其需求。然后,你需要重写new和/或malloc、delete和/或free函数,以从/向该缓冲区返回内存。
实现这种解决方案时,你需要编写自己的分配器(从缓冲区中获取资源),并且可能会使用多个分配器,这通常是为什么首先要分配内存池的原因。
默认的内存分配器是一个很好的全能分配器,但并不适用于所有分配需求。例如,如果你知道将为特定大小分配很多对象,则可以定义一个分配器,该分配器分配固定大小的缓冲区并预先分配多个以获得一些效率。

4
这是经典的分配器,也是非多线程使用时最好的之一:

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上提供的参考资料太好了。我一直在想如何管理它们,因为我的记忆力有限 :-(。 - Praveen S

1

1
是的,stdlib堆和操作系统堆/虚拟内存都非常麻烦。操作系统调用非常慢,stdlib更快,但仍然有一些“不必要”的锁定和检查,并且会为已分配块增加显着的开销(即除了您分配的内存外,还用于管理的一些内存)。 在许多情况下,完全可以通过使用静态结构来避免动态分配。例如,有时最好(更安全等)为Unicode文件名定义一个64k静态缓冲区,而不是定义指针/ std:string并动态分配它。 当程序必须分配很多相同结构的实例时,分配大型内存块然后只需将实例存储在其中(按顺序或使用空闲节点的链表)比逐个分配实例要快得多-C ++具有用于此的“放置新”。 在许多情况下,在处理变量大小对象时,可能的尺寸集实际上非常有限(例如,类似于4 + 2 *(1..256)),因此可以使用像[3]这样的几个池,而无需收集垃圾,填充间隙等。 针对特定任务的自定义分配器通常比标准库中的分配器快得多,甚至比速度优化但太通用的实现还要快。 现代CPU /操作系统支持“大页面”,当您显式使用大块时,可以显着提高内存访问速度-请参阅 http://7-max.com/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接