如何使用boost :: pool库创建自定义内存分配器 [英] How to use boost::pool library to create a custom memory allocator

查看:208
本文介绍了如何使用boost :: pool库创建自定义内存分配器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am new to boost and I want to know how exactly the boost::pool libraries can help me in creating a custom memory allocator. And I have two vector of struct objects. First vector is of structure type A, while second vector is of structure type B. How can I reuse the memory allocated to the first vector to the second vector.

推荐答案

Boost Pool是定义一些分配器类型的库.

Boost Pool is a library that defines a few allocator types.

很明显,该库的重点是提供池分配器.

Obviously, the focus of the library is to provide Pool Allocators.

当分配相同大小的对象时,池分配器会发光.

Pool Allocators shine when you allocate objects of identical size.

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

Note If your structure A and structure B aren't identical/very similar size you may not like this design assumption.

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

The allocators provided by the framework work with singleton pools, and they differentiate on the size of your container value_type. That's a bit inflexible if you want to reuse or even share the pool between different value-types. Also, singleton pools can be inflexible and imply thread-safety costs.

所以,我想看看我是否可以简化最简单的分配器,以缓解其中的一些问题.

So, I wanted to see whether I could whip up the simplest allocator that alleviates some of these issues.

我将源代码用于boost::pool_alloc,并使用 cppreference示例 ,然后进行了一些测试和内存分析.

I used the source to boost::pool_alloc and the cppreference example as inspiration, and then did some testing and memory profiling.

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

Here's the simplest pool allocator I could think of:

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:

On my compilers it works for both std::vector and Boost's vector:

  • Live On Coliru - with GCC std::vector
  • Live On Coliru - with GCC boost::container::vector
  • Live On Coliru - with Clang std::vector
  • Live On Coliru - with Clang boost::container::vector

所有运行均无泄漏,并且运行ubsan/asan.

All runs are leak-free and ubsan/asan clean.

请注意,如果元素类型适合请求大小(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的Memory profiler显示,并注释掉release_memory行,如下所示:

Profiling

Using Valgrind's Memory profiler shows, with the release_memory lines commented out as shown:

in 中对release_memory()通话进行评论时:

When commenting in the release_memory() calls:

我希望这看起来像您想要的东西.

I hope this looks like the thing you wanted.

此分配器使用现有的pool,后者将其委托回malloc/free来按需分配内存.要将其与固定的领域"一起使用,您可能更喜欢直接使用simple_segregated_storage.本文看起来像是一个很好的入门书 https://theboostcpplibraries.com/boost.pool

This allocator uses the existing pool which delegate back to malloc/free to allocate memory on demand. To use it with a fixed "realm", you might prefer using simple_segregated_storage directly. This article looks like a good starter https://theboostcpplibraries.com/boost.pool

这篇关于如何使用boost :: pool库创建自定义内存分配器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆