【问题标题】:Custom pooled allocator in C++ besides boost::pool除了 boost::pool 之外的 C++ 中的自定义池分配器
【发布时间】:2013-02-11 13:12:05
【问题描述】:

我在 C++ 中有一个使用场景,我多次调用的函数会创建一些本地的、小但动态大小的向量。在分析我的程序后,我注意到在 std::vector::free() 中花费了过多的时间。对此类问题的自然(C++ 式)解决方案似乎是将默认分配器切换为更适合我的使用场景的东西。特别是,在这里使用内存池策略似乎很有意义。然而,到目前为止, boost::pool_alloc 一直是个麻烦。我已经让它工作了,但是虽然在我的小但经常调用的函数(我们将调用该函数 f())中分配更快,但它会导致调用 f() 的函数在返回之前挂起 很长时间。

然而更多的分析表明,所有的时间(在我厌倦等待之前的几十分钟)都花在了 pool_allocator::ordered_free() 上。我在一个简单的测试程序中重现了同样的行为(虽然不是那么极端),而且看起来,事实上,当大量构造的向量将它们的内存返回到单例池时,函数在返回之前会挂起很长时间.

如果有人知道避免这种行为的方法,或者知道另一个不会遇到这种问题的 C++ 池分配器,我将非常感激!

【问题讨论】:

  • reserve-ing 正确确实可以提供帮助(如果您还没有)。
  • 嗨,贾斯汀,是的,我已经在保留向量了。问题是我在函数调用时知道每个向量的大小(即它们没有增长),但在编译时不知道,所以它们仍然是动态的。

标签: c++ boost stl malloc allocator


【解决方案1】:

我自己写过几次,一旦一切顺利,分配和释放都非常快。 1. 按大小创建池映射。 2. 每个池都有一个块的双向链表。 3.每个块的前后都有额外的空间,用于列表节点和所有者池引用,大小检查等 4. 分配速度很快,因为您只需要查找大小 >= 您的块大小的第一个池并取消列出第一个条目。 5. 释放速度很快,因为你在内存块中有一个指向池的指针,所以你所要做的就是重新列出它。 6.你可以在启动时创建一堆空池。然后,在每个分配上,首先尝试从池中取消列表。如果失败,那么 malloc() 代替。当块被释放时,将其添加回池中而不是释放它。 7. 一旦你的应用程序稳定运行,所有的 allocs 将直接来自 pools 链表,frees 将直接回到那里......超级快。 8. 当你的程序退出时,Free() 池中的所有内存。

【讨论】:

    【解决方案2】:

    根据你的问题,我认为

    • 只有一个功能
    • 向量的大小是有限的(你说它很小)
    • 该函数不经常递归调用

    如果是这种情况,请考虑使用堆栈分配的内存而不是动态分配的内存。您可以通过不使用向量但使用std::array<> 和一些大小指示符(如果存储的类型是可构造的)或一些固定大小和放置新的原始内存缓冲区来做到这一点,或者将后者包装到分配器类中以使用向量那个分配器类。

    如果您的性能问题仅限于这么小的代码区域,我不会使用诸如 boost::pool 之类的通用内存管理工具,而是针对当前情况推出一些非常专业的工具。

    【讨论】:

    • 嗨阿恩。存储的类型很容易构造(它是 size_t)。但是,我不能真正使用堆栈分配的存储,因为场景比我最初所说的要复杂一些。特别是,虽然在每个函数调用中都会创建大量向量,并且大多数向量在函数返回之前被销毁,但其中一小部分确实会合并到其他堆对象中并转义函数。我想我可以只复制这些向量(而不是移动)。我想避免编写自己的自己的分配器,但这可能是最好的前进方式。
    • 如果您事先知道哪些向量被移动到堆对象中,您可以为它们使用标准分配器。
    猜你喜欢
    • 2011-02-24
    • 2011-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-11
    • 2012-02-22
    相关资源
    最近更新 更多