【问题标题】:Why design custom memory manager?为什么要设计自定义内存管理器?
【发布时间】:2019-10-03 15:43:13
【问题描述】:

我过去曾设计过简单的固定块存储管理器 (SM) 和通用内存管理器。在这两种情况下,我都会在启动时分配一大块堆内存并一次又一次地重新使用释放的内存,从而防止频繁调用昂贵的 ma​​lloc/new 调用。

如果我谈论固定块 SM (Github link),那么我实际上已经看到了它带来的性能优势。在我的例子中,随机大小分配大约提高了 40%。

但对于通用内存管理器 (Github link)(没有内存池),我没有看到任何明显的性能提升。我能看到的唯一收获是访问内存使用统计信息。性能方面,由于确定空闲块(分配期间)和映射中的内存位置(释放期间)的开销,它会变得更慢。

所以我的问题是,自定义通用内存分配器在什么情况下会有用?值得付出努力吗?

【问题讨论】:

  • 是的。如果您可以在内存管理器中平衡速度、简单性和可移植性,那么收益将远远超过工作。
  • malloc()new() 不是系统调用。像mmapbrk() 这样的低级别的东西。
  • @JL2210 即便如此,由 C 或 C++ 代码进行的调用实际上是包装底层系统调用的 函数 调用,甚至不必调用 @ 987654328@ 或brk()。例如,open()“系统调用”是一个可以包装openat() system call 的函数。我个人讨厌将库函数人为地和误导性地划分为“函数”和“系统调用”。
  • 您是在询问该特定(相当天真,IMO)实现的潜在应用,还是一些为特殊目的设计的抽象自定义内存管理器的潜在应用?
  • @AndrewHenle 正确(虽然函数名称是brk(),而不是break())。

标签: c++ c memory memory-management


【解决方案1】:

性能并不是开发自定义分配器的唯一原因。 其他原因可能包括:

  1. 更好的调试功能
    如果有一个内存管理器可以帮助定位一些常见的编程错误,比如使用未初始化的内存、访问分配块之外的内存、双重释放、释放后使用,这不是很好吗?但是,一个好的操作系统内存管理器可能已经提供了所有这些开箱即用的功能。
  2. 强加内存使用配额
    在较大的项目中,您可能会担心内存占用,尤其是在使用某些第三方模块的情况下。最好不要让流氓模块让所有其他模块都饿死。
  3. 保证分配
    有时您想确保某个关键功能永远不会失败。预分配大量内存并提供自定义分配器可能是所需的步骤之一。
  4. 在不受信任的插件之后强制清理内存
    保护您的应用免受与内存消耗相同的不健康情况。
  5. 独立系统可能根本没有任何内存管理器。 :-)

【讨论】:

    【解决方案2】:

    通常,构建自定义分配器的最大动力与性能无关。相反,需要在各种系统上运行的程序会遇到不一致和/或不完整的库。尤其是标准库。此外,嵌入式系统的硬件限制经常要求应用程序非常小心内存使用和管理。这些程序运行一切,从汽车的空调到飞机上的自动驾驶仪。还有一些系统没有堆栈,需要仔细管理堆。这些例子只是冰山一角。再加上一个基本的分配器,就像许多基于堆栈的设计之一,你会得到一个非常简单的编写、易于维护和高性能的解决方案。编写自己的分配器的另一个原因很简单,就是内存不足。当有大量“空闲”内存但没有足够大的块来填充请求时,通常会出现这个问题。含义内存在分配器中变得支离破碎。以谷歌“facebook 内存分配器”为例。

    所有这些程序的一个共同主题是需要一个解决方案特定的内存管理器。这就是有这么多免费可用的管理器的原因。如果没有特殊需要,那么没有充分的理由使用除 malloc/new 之外的任何东西。或者,甚至更好地制定需要使用智能指针来处理幕后内存分配的策略。内存分析和统计很容易使用外部工具完成,通常是程序员在通往解决方案特定内存管理器的道路上迈出的第一步。您永远不应该从“通用内存管理器”开始,然后再问“我为什么要使用它”。

    最后,您对“存储管理器”一词的使用指的是一类更广泛的工具,这些工具通常管理从短期内存到长期存储和归档的数据。这些工具非常少见,可能非常复杂,而且还是一种解决方案特定工具,需要用于满足特定需求(例如数据库)。

    性能通常是在程序中包含内存管理器的最后一个原因,也就是说,如果内存管理器的性能不能超过系统的至少 2 倍,那么就会出现严重错误。要么程序为经理找到了退化案例,要么经理本身有问题需要解决。

    【讨论】:

      【解决方案3】:

      很少需要设计自定义内存管理器。那里有这么多,大多数人可以找到一个现成的使用。几年前,我有一个包含解释器的 C++ 系统。在最初的测试中,它并没有我们希望的那么快。分析表明问题出在内存分配上,它出现在字符串类中我们从互联网上下载了大约两打内存管理器,并依次尝试了它们中的每一个。我们能够在速度上获得巨大的提升。我们最终使用的内存管理器总是分配大小为 2 的幂的块,并为每个块大小维护单独的池。

      我们发现的内存管理器数量超出了我们的测试范围。

      【讨论】:

      • 当我使用固定块内存管理器(每个块大小有不同的池)时,我什至注意到性能提升。
      • 我怀疑大多数使用固定块大小的内存管理器都来自对首次拟合和最佳拟合算法的学术分析。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多