【问题标题】:making your own malloc function?制作自己的 malloc 函数?
【发布时间】:2011-01-16 04:20:31
【问题描述】:

我读到有些游戏会重写自己的 malloc 以提高效率。我不明白这在虚拟内存世界中是如何实现的。如果我没记错的话,malloc 实际上调用了一个特定于操作系统的函数,它使用 MMU 将虚拟地址映射到真实地址。那么,如何在不调用实际运行时的 malloc 的情况下制作自己的内存分配器并分配实际内存呢?

谢谢

【问题讨论】:

  • 很可能他们正在预分配一大块内存(“内存竞技场”),这样可以避免碎片并提高分配性能
  • 是的,您可以向操作系统请求一大块连续内存 Milo。这在系统世界中很常见。
  • 是的,他们最有可能做的是在他们使用的 malloc 周围编写一个包装器,而不是直接调用 malloc,这在某些情况下确实会提高速度,但不会取代操作系统级别的东西
  • 如果他们真的在重写malloc 而不仅仅是在malloc 之上使用专用池,我认为这只是他们愚蠢的问题。
  • @R..:当前一代的游戏机可能更好,因为游戏在操作系统下运行而不是替换它。

标签: c malloc


【解决方案1】:

当然可以编写比通用分配器更高效的分配器。

如果您知道分配的属性,则可以将通用分配器从水中淘汰。

举个例子:很多年前,我们不得不为嵌入式系统设计和编写一个通信子系统(HDLC、X.25 和专有层)。我们知道最大分配总是小于 128 字节(或类似的东西)的事实意味着我们根本不必处理可变大小的块。 每个分配128字节,不管你要求多少。

当然,如果你要求更多,它返回 NULL。

通过使用固定长度的块,我们能够大大加快分配和解除分配的速度,使用位图和相关结构来保存记帐信息,而不是依赖较慢的链表。此外,不需要合并释放的块。

当然,这是一种特殊情况,但您会发现游戏也是如此。事实上,我们甚至在一个通用系统中使用了这一点,在该系统中,低于某个阈值的分配从一个自我管理的预分配池中以相同的方式获得了固定数量的内存。任何其他分配(大于阈值或如果池已完全分配)被发送到“真实”malloc

【讨论】:

  • 只要您不必处理线程,使用正确分箱算法的通用分配器同样快速且功能强大得多。不过,我承认,一旦并发发挥作用,您的位图等可能会更快和/或更简单。
  • 通用分配器几乎总是(我认为总是如此,我自己,但我不会那么傲慢)被具有额外知识优势的分配器击败。沿着减少荒谬的路线,如果你知道一次只有一个分配会被激活并且它总是小于 1K,你可以在你的 malloc 中有一个静态缓冲区 :-) 有 no 可以胜过它的分箱分配器。你是对的,这是一种权衡,灵活性与速度,但这就是问题所在 - 游戏可能不需要所有的灵活性。
  • 我写了一篇关于这个主题的综合研究。要点是,与最先进的内存分配器相比,自定义内存分配器的性能优势通常低于宣传的。见cs.umass.edu/~emery/pubs/berger-oopsla2002.pdf
  • 我会在@Emery 上听从你的意见,因为你所做的调查比我们所做的更彻底。我们确实发现我们的自定义分配器(就像您研究中的两个)比通用分配器要好得多,但到那时最先进的技术可能已经改进了很多。与所有优化一样,衡量,不要猜测。
【解决方案2】:

仅仅因为malloc() 是标准C 函数并不意味着它是您对内存系统的最低级别访问。事实上,malloc() 可能是根据较低级别的操作系统功能实现的。这意味着您也可以调用那些较低级别的接口。它们可能是特定于操作系统的,但它们可能使您获得比从malloc() 接口获得的更好的性能。如果是这种情况,您可以以任何您想要的方式实现自己的内存分配系统,并且可能会更有效 - 例如,针对您将要进行的分配的大小和频率的特征优化算法.

【讨论】:

    【解决方案3】:

    一般来说,malloc 会调用一个特定于操作系统的函数来获取一堆内存(至少一个 VM 页面),然后根据需要将该内存分成更小的块返回给 malloc 的调用者。

    malloc 库还将有一个(或多个)空闲块列表,因此它通常可以满足请求而无需向操作系统请求更多内存。确定要处理多少个不同的块大小,决定是否尝试合并相邻的空闲块等等,是 malloc 库实现者必须做出的选择。

    您可以绕过 malloc 库并直接调用操作系统级别的“给我一些内存”功能,并在您从操作系统获得的内存中进行自己的分配/释放。这样的实现可能是特定于操作系统的。另一种选择是使用 malloc 进行初始分配,但保留您自己的已释放对象缓存。

    【讨论】:

      【解决方案4】:

      您可以做的一件事是让您的分配器分配一个内存池,然后为来自 than 的请求提供服务(如果内存用完,则分配一个更大的池)。我不确定他们是否正在这样做。

      【讨论】:

        【解决方案5】:

        如果我没记错的话,malloc 实际上是 调用特定于操作系统的函数

        不完全是。大多数硬件的页面大小为 4KB。操作系统通常不会公开提供小于页面大小(和页面对齐)块的内存分配接口。

        malloc 将大部分时间用于管理已分配的虚拟内存空间,并且只是偶尔向操作系统请求更多内存(显然这取决于您分配的项目的大小以及您free 的频率)。

        有一个常见的误解,即当您free 某事时,它会立即返回给操作系统。虽然有时会发生这种情况(特别是对于较大的内存块),但通常情况下,freed 内存仍然分配给进程,然后可以被以后的mallocs 重新使用。

        因此,大部分工作是记录已分配的虚拟空间。分配策略可以有很多目标,例如快速操作、低内存浪费、良好的局部性、动态增长的空间(例如realloc)等等。

        如果您更了解自己的内存分配和释放模式,可以针对您的使用模式优化mallocfree 或提供更广泛的接口。

        例如,您可能分配了许多大小相同的对象,这可能会改变最佳分配参数。或者您可能总是一次释放大量对象,在这种情况下您不希望 free 做一些花哨的事情。

        看看memory poolsobstacks

        【讨论】:

          【解决方案6】:
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-08-30
          • 2015-07-18
          相关资源
          最近更新 更多