c++ - 如果内存池比malloc快,为什么malloc不能在幕后使用它们?

标签 c++ c malloc memory-pool

我一直听到,内存池在分配内存时可以显着提高性能..那么为什么传统的malloc实现不以某种方式使用它们呢?

我知道部分原因是内存池使用固定大小的内存块,但似乎有些不使用,它们唯一需要做的就是预先获取一些额外的内存。有没有一种方法可以针对这些目的对其进行充分概括?

最佳答案

内存池可能比通用内存分配更有效,但通常仅是因为您具有有关分配模式的额外信息。它们最重要的特性也许是它们在运行时具有确定性,例如在实时操作系统中尤为重要。
作为示例,我曾经编写了一个嵌入式系统,在该系统中,我知道所需的最大分配是128字节(以下称为块)。为此,我维护了一组连续的块,并使用映射来确定一个块是否空闲。
它最初是位图,但最终通过将每个已使用/未使用标志存储在单独的字节中而最终获得了更高的性能。映射的内存使用量是映射的八倍,但是,由于已知池大小并且受到合理限制(一千个左右),因此还算不错。而且它无需花很多时间就可以进行池管理,从而为我们提供了更快的速度。
我们还添加了其他优化措施,例如存储第一个空闲块,以便我们可以快速找到它。维护起来很容易,因为:

  • 释放比当前最低价低的块将仅更新最低价;和
  • 分配最低的块只会增加最低的块-虽然不能保证它指向一个空闲块,但它仍然可以使搜索更快,并且避免了不必要的分配搜索(例如,如果您首先释放了一个低于您刚分配的区块)。

  • 然后,如果您要求的大小超过了块大小,则它返回NULL(这在该系统中从未发生过,但是由于偏执,我为它编写了代码,以防万一。)如果您请求适合块的内容,则无论如何都将获得一个完整的块(但是,当然,您仍应只使用所需的内存,以防万一我想稍后更改块大小或从单独的块中进行分配具有不同块大小的池)。
    事实证明,这要比当时的通用分配器快得多,因为它们必须处理不同的请求大小,并担心在释放内存时合并连续的空闲块之类的事情。
    但这需要额外的知识,即没有分配会超过块大小这一事实。

    另一个模型是为小于一定大小的请求提供一个池,但如果存在以下情况,则恢复为常规分配:
  • 您请求的块超出了块大小;或
  • 池当前已耗尽。

  • 在大多数情况下,这可以使您获得额外的效率(当然,这取决于您的分配模式),但可以进行超出此范围的分配。它需要为请求分配大小和池耗尽进行评估,因此在每个分配中都需要付出一些额外的努力,但仍可能会超出一般情况。

    As an aside, I recall something similar in Java strings (not sure if this is still the case, I haven't used Java for quite a while). The string object allocation had a buffer inside it for storing small strings but could also use that space to store a pointer for a separately allocated chunk of characters (if it was bigger than the internal buffer). This reduced fragmentation (and dereferencing) for what was possibly a large number of small strings, but still allowed for larger strings if needed.



    有趣的是,我曾经尝试在CPython源代码中进行实验,以查看内存池是否可以提高性能,特别是考虑到其中存在的内存分配量。它使用与上面给定的策略类似的策略,优先从池中进行分配,但是如果请求的大小超出了块大小或池已用尽,则恢复为原始策略。
    再次,它具有所讨论的优化,然后是一些优化。例如,最后释放的块已被缓存,因此可以立即分发它,而无需对池进行任何搜索,以试图加快many-times(single-free-then-allocate)模式。
    但是,即使进行了各种优化,池和块大小,它似乎也与我编写的用于测试它的一些测试代码的性能没有实质性的区别,这使我相信CPython中使用的实际分配器已经相当不错了。

    关于c++ - 如果内存池比malloc快,为什么malloc不能在幕后使用它们?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61687665/

    相关文章:

    c - 如何分配 UINT_MAX 的 block 大小?

    c - Optarg 和命令行参数

    c - 将二维数组分配给结构体对象

    c++ - DD/MM/YYYY 输入验证

    c++ - pthread_join() 在 iOS 上失败

    c++ - C语言中&(AND)运算符有什么用?

    c - 检测进程是否空闲

    c - 是什么导致我的数组充满了不需要的数字

    c++ - 如何从输入 C++ 中分别读取整数和分数

    c - 假设内存页面大小是 2 的幂是否安全?