如何实现内存堆

时间:2010-12-21 03:21:42

标签: c++ c memory heap allocation

不确定如何标题,但问题是:

我听说过程序员在程序开始时分配大部分连续内存,然后在必要时将其处理掉。这与每次需要内存时简单地访问操作系统形成对比。 我听说这会更快,因为它可以避免不断向操作系统询问连续内存块的成本。

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

我的问题是,如何实际实现这一目标?

谢谢, dragonwrenn

5 个答案:

答案 0 :(得分:14)

大多数C和C ++编译器已经提供了堆内存管理器作为标准库的一部分,因此您根本不需要做任何事情以避免每次请求都触及操作系统。

如果你想提高性能,你可以简单地链接和使用一些改进的分配器。例如Hoard,哪个小伙子在一个现已删除的答案中提到(实际上非​​常好 - 小麦,为什么要删除它?)。

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

  • 从操作系统中请求大块内存
  • 保留免费区块的链接列表
  • 当分配请求进入时:
    • 在列表中搜索一个足以满足所请求大小的块以及一些存储在一起的簿记变量。
    • 为当前请求拆分了足够大块的块,将其余部分放回到免费列表中
    • 如果没有足够大的块,请返回操作系统并要求另一个大块
  • 当发布重新分配请求时
    • 阅读标题以找出尺寸
    • 将新释放的块添加到空闲列表
    • 可选地,查看紧接着的内存是否也列在空闲列表中,并将两个相邻的块组合成一个更大的块(称为合并堆)

答案 1 :(得分:6)

您可以在程序开头分配一大块内存,以满足其需求。然后你必须覆盖new和/或malloc,delete和/或free来从/向这个缓冲区返回内存。

实现这种解决方案时,您需要编写自己的分配器(从块中获取源代码),并且最终可能会使用多个分配器,这通常是您首先分配内存池的原因。

默认内存分配器是一个很好的全面分配器,但不是最适合所有分配需求。例如,如果您知道要为特定大小分配大量对象,则可以定义一个分配器,该分配器分配固定大小的缓冲区并预先分配多个以获得一定效率。

答案 2 :(得分:3)

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

http://g.oswego.edu/dl/html/malloc.html

通过阅读其设计说明,您可以学到很多东西。

话虽如此,除非你的程序有非常不寻常的分配模式,否则编写自己的分配器或使用自定义分配器可能是一个非常糟糕的主意。特别是如果您尝试替换系统malloc,则可能会将来自不同库(或标准库函数)的各种错误和兼容性问题与“错误版本的malloc”链接起来。 / p>

如果您发现自己只需要针对少数特定任务进行专门分配,则可以在不替换malloc的情况下完成。我建议为固定大小的对象查找GNU obstack和对象池。这些涵盖了大多数专业分配可能具有实际用途的案例。

答案 3 :(得分:1)

  1. 是的,stdlib堆和OS堆/虚拟内存都非常麻烦。 操作系统调用非常慢,而且stdlib速度更快,但仍有一些“不必要的” 锁定和检查,并为分配的块增加了大量开销 (即除了你分配的内容之外,还有一些内存用于管理。)
  2. 在许多情况下,可以完全避免动态分配, 通过使用静态结构代替。例如,有时它更好(更安全等)来定义64k 用于unicode文件名的静态缓冲区,而不是动态定义指针/ std:string 分配它。
  3. 当程序必须分配大量相同结构的实例时,它 分配大内存块然后只在那里存储实例要快得多 (顺序或使用自由节点的链接列表) - C ++有一个“新的位置”。
  4. 在许多情况下,使用varible-size对象时,可能的大小集合 实际上非常有限(例如4 + 2 *(1..256)之类的东西),所以它可以使用 像[3]这样的几个游泳池,不需要收集垃圾,填补空白等。
  5. 对于特定任务的自定义分配器来说,它通常要快于一个(s) 来自标准库,甚至比速度优化更快,但实现过于通用。
  6. 现代CPU /操作系统支持“大页面”,可以显着改善内存 明确使用大块时的访问速度 - 请参阅http://7-max.com/

答案 4 :(得分:1)

IBM developerWorks有一篇关于内存管理的好文章,有一个广泛的资源部分供进一步阅读:Inside memory management

维基百科也有一些很好的信息:C dynamic memory allocationMemory management