7

我是 boost 新手,我想知道 boost::pool 库究竟如何帮助我创建自定义内存分配器。我有两个结构对象向量。第一个向量的结构类型为 A,而第二个向量的结构类型为 B。如何将分配给第一个向量的内存重用于第二个向量。

4

1 回答 1

15

Boost Pool 是一个定义了一些分配器类型的库。

显然,库的重点是提供池分配器。

当您分配相同大小的对象时,池分配器会大放异彩。

注意如果您的结构A和结构B大小不同/非常相似,您可能不喜欢这种设计假设。

框架提供的分配器与单例池一起使用,它们根据容器 value_type 的大小进行区分。如果您想在不同的值类型之间重用甚至共享池,这有点不灵活。此外,单例池可能不灵活并且意味着线程安全成本。

所以,我想看看我是否可以设计出最简单的分配器来缓解其中的一些问题。

我以源代码boost::pool_alloccppreference 示例为灵感,然后进行了一些测试和内存分析。

更灵活的状态分配器

这是我能想到的最简单的池分配器:

using Pool = boost::pool<boost::default_user_allocator_malloc_free>;

template <typename T> struct my_pool_alloc {
    using value_type = T;

    my_pool_alloc(Pool& pool) : _pool(pool) {
        assert(pool_size() >= sizeof(T));
    }

    template <typename U>
    my_pool_alloc(my_pool_alloc<U> const& other) : _pool(other._pool) {
        assert(pool_size() >= sizeof(T));
    }

    T *allocate(const size_t n) {
        T* ret = static_cast<T*>(_pool.ordered_malloc(n));
        if (!ret && n) throw std::bad_alloc();
        return ret;
    }

    void deallocate(T* ptr, const size_t n) {
        if (ptr && n) _pool.ordered_free(ptr, n);
    }

    // for comparing
    size_t pool_size() const { return _pool.get_requested_size(); }

  private:
    Pool& _pool;
};

template <class T, class U> bool operator==(const my_pool_alloc<T> &a, const my_pool_alloc<U> &b) { return a.pool_size()==b.pool_size(); }
template <class T, class U> bool operator!=(const my_pool_alloc<T> &a, const my_pool_alloc<U> &b) { return a.pool_size()!=b.pool_size(); }

笔记:

  • 此分配器是有状态的,因此需要允许它们的容器实现(例如 Boost Container、Boost MultiIndex)。理论上,所有符合 C++11 的标准库也应该支持它们
  • 比较应该指导容器交换/复制分配器与否。这不是我很关心的一个领域,并且选择的方法来标记所有不同请求大小的池可能对某些人来说是不够的。

样品,测试

在我的编译器上,它适用于std::vector和 Boost 的vector

所有运行均无泄漏且 ubsan/asan 清洁。

请注意我们如何将同一个池与不同结构大小的不同容器重用,以及我们如何甚至一次将它与多个活动容器一起使用,前提是元素类型适合请求大小 (32)

struct A { char data[7];  };
struct B { char data[29]; };

int main() {
    //using boost::container::vector;
    using std::vector;

    Pool pool(32); // 32 should fit both sizeof(A) and sizeof(B)
    {
        vector<A, my_pool_alloc<A> > v(1024, pool);
        v.resize(20480);
    };

    // pool.release_memory();

    {
        vector<B, my_pool_alloc<B> > v(1024, pool);
        v.resize(20480);
    }

    // pool.release_memory();

    // sharing the pool between multiple live containers
    {
        vector<A, my_pool_alloc<A> > v(512, pool);
        vector<B, my_pool_alloc<B> > w(512, pool);
        v.resize(10240);
        w.resize(10240);
    };
}

剖析

使用 Valgrind 的内存分析器显示,release_memory注释掉的行如下所示:

在此处输入图像描述

电话中发表评论时release_memory()

在此处输入图像描述

我希望这看起来像你想要的东西。

进一步的想法:简单的隔离存储

这个分配器使用现有的pool哪个委托回 malloc/free 来按需分配内存。要将它与固定的“领域”一起使用,您可能更喜欢simple_segregated_storage直接使用。这篇文章看起来像是一个很好的入门https://theboostcpplibraries.com/boost.pool

于 2018-02-14T23:51:01.837 回答