首页 > 解决方案 > 当我可以覆盖 new 和 delete 时,为什么还要为 STL 容器编写自定义分配器?

问题描述

我想编写一个自定义内存管理器/分配器来学习。我很想拥有一个从堆中请求 n 字节内存的主分配器(通过新的)。后面会跟着几个分配器……适配器?每个都将与 master 接口,请求管理一块内存,这些将是堆栈、线性、池、slab 分配器等,每个分配器都管理来自它们的主池分配器切片的分配。

我遇到的问题是我是否应该为各种 STL 容器编写自定义 allocator_traits 来与这些接口;或者,如果我应该忽略适配器的想法并简单地重载 new 并删除以使用自定义池分配器/管理器,即主分配器。

我有兴趣了解的是,我将从为 STL 容器使用单独的分配器中获得什么切实的好处?似乎默认的 std::allocator 会根据需要调用 new 和 delete ,所以如果我重载它们以从我的大型自定义内存池中请求,我将获得所有好处,而无需自定义 std::allocator 代码。

或者这是某些类型的分配器模型(例如为 std::deque 使用堆栈分配器)比默认分配器工作得更好的问题?如果是这样,普通的 stl 实现是否已经为各种容器类型专门化了默认分配器,或者在对默认分配器的调用中进行了优化?

如果这很重要,我正在通过 GCC 10+ 使用 C++20

标签: c++memory-managementdynamic-memory-allocationc++20allocator

解决方案


如果你想替换全局分配器,包括你正在使用的每个库,你不必使用std::allocator.

std 分配器让你可以做一些事情,比如创建临时分配池。假设您有一些可以保证不会超过某个范围的数据结构,并且您知道(无论分配什么)90%+ 将保持分配到范围的末尾。

new一个相对简单的 std 分配器可以分配内存,从不回收它,并在作用域的末尾清理它,这比任何全局或运算符都快得多delete

只要您对容器的内容和生命周期模式有专门的了解,就可以为该特定容器手动调整分配器。标准分配器不能。有时,当您愿意做出标准容器不具备的妥协时,您可以使用自定义分配器修补它们的行为。

std::deque不能有效地使用堆栈分配器,因为它不能假定您主要将其用作堆栈。您可能主要将其用作队列。当您主要将堆栈分配器用作队列时,它将是一场灾难。但是如果您将 90%+ 用作堆栈,则堆栈分配器可能会更快,但会以适度的内存开销为代价(如果 99%+,则堆栈分配器会处理异常情况并清理基于非堆栈的操作)。

最后,分配器可以让你区分容器的种类。您可能希望将文档(持久)状态的内存分配在一个内存区域中,并将“临时”非持久数据分配到其他地方。

是的,使用 std 分配器是您不应该考虑的事情。优化是可替代的,调整低级内存分配是您在使系统的其余部分更高效和更实用之后可以进行的工作。只有当你有一些可行的东西,速度不够快,并且你已经确定新/删除是一个基本的瓶颈时,你才能说“好的,是时候替换分配了!”


推荐阅读