linux stl内存池的应用

在stl里面,stl对容器中元素内存的分配,与元素的构造、析构过程进行了分离

 c++ 在全局定义了 operator new(size_t size), 调用malloc(size)

operator new(size_t size,void* buf) 什么也不做直接return buf

operator delete(void* buf); 调用free(buf)

对于ClassA* ptr = new ClassA(),编译器步骤为(分配内存+调用构造函数)

void * mem=operator new(sizeof(ClassA));

ClassA* ptr=(ClassA*)mem;

ptr->ClassA::ClassA();

对于new(_mem) ClassA(), 编译器步骤为(使用已分配的内存(内存需要对齐) + 调用构造函数,相当于分离分配过程)

void* mem = operator new(sizeof(ClassA),_mem); //其实什么也没做,直接返回mem

ClassA* ptr=(ClassA*)mem;

ptr->ClassA::ClassA(); //通过指针直接调用时,无法编译

可以使用stl里面实现的标准内存分配器std::allocator

在windows上其使用_Default_allocate_traits实现空间分配,比较直接使用 operator new直接分配,施放则是直接调用_Deallocate函数使用operator delete释放

在linux上是使用new_allocator类进行分配、释放,也是直接operator new、operator delete

allocator<Foo> alloc;
//Allocate memory for one or n objects,根据Foo对象内存对齐后的原始内存
auto p = alloc.allocate(1);
//Construct an object of Foo on allocated memory block p, by calling one of Foo's constructors
alloc.construct(p, args, ...);

//OK, p now points to a Foo object ready for use...

//Call Foo's destructor but don't release memory of p
alloc.destroy(p);
//Release memory
alloc.deallocate(p, 1);

在linux上,编译器版本为9.4.0扩展了mt_alloc,适用于单线程、多线程,具有内存池功能; 分为一级管理与二级管理,一级管理直接new、delete,二级管理采用内存池。默认情况大于128bytes使用一级管理,小于采用二级管理;当采用二级管理时,每次申请都是先查询释放链表有没有释放过的,有释放过的先复用,然后才是在内存池中割一块新的,或者重新分配一块

#include <ext/mt+allocator.h>
int main(argc , char **argv)
{
    //__ommon_pool_policy模板参数bool表示是否用于多线程
    typedef __gnu__cxx::__mt_alloc<<XXXX>, __gnu_cxx::__common_pool_policy<__gnu_cxx::_pool, false>> MtPoolAlloc;
    typedef __gnu_cxx::__pool_base::_Tune MtPoolAllocTune;
    
    MtPoolAlloc alloc;
    /*
    size_t _M_align; //字节对齐
    size_t _M_max_bytes; //默认为128,表示128字节以上的用new直接分配
    size_t _M_min_bin;//可分配的最小的内存大小,默认为8
    size_t _M_chunk_size;//每次从os申请的内存块的大小,默认为4096 - 4 *sizeof(void*)
    size_t _M_max_threads;//可支持的最多的线程数,默认4096
    size_t _M_freelist_headroom;//单线程能保存的空闲块的百分比,默认10%
    bool   _M_force_new;//是否直接使用new和delete
    */
    MtPoolAllocTune opt{8, sizeof(XXXX), sizeof(XXXX), 4096 - 4 * sizeof(void*), 1, 10, false};
    //alloc._M_get_options可以返回正在使用的,修改部分也可以
    alloc._M_set_options(opt);
    auto *tt1 = alloc.allocate(1);
    alloc.construct(tt1, 1, 2);//调用构造函数
    std::cout << reinterpret_cast<unsigned long long>((void*)tt1) << std::endl;
    alloc.destroy(tt1); //调用析构函数; 如果析构是虚函数,没有调用构造函数的话,这里会崩溃
    alloc.deallocate(tt1, 1); //放回内存池
    tt1 = alloc.allocate(1);
    alloc.construct(tt1, 1, 2);//调用构造函数
    std::cout << reinterpret_cast<unsigned long long>((void*)tt1) << std::endl;
    alloc.destroy(tt1);
    alloc.deallocate(tt1, 1); //放回内存池
}

运行结果为:

94504784214136
XXXX() //构造函数打印
~XXXX() //析构函数打钱
94504784214136
XXXX() //构造函数打印
~XXXX() //析构函数打钱

与allocator这一类分配器,相配对的还有专门的stl算法函数,如uninitialized_copy、uninitialized_copy_n、uninitialized_fill、uninitialized_fill_n等,都是把输入源拷贝到已分配(但未初始化)的内存上,在对应位置直接调用对应的类的拷贝构造函数

自定义allocator,范例如下

#include <vector>
#include <ext/mt_allocator.h>

template<typename T>
class SelfAlloc{
    public:
    typedef T value_type;

    SelfAlloc() = default;

    template<typename T1>
    SelfAlloc(const SelfAlloc<T1>& other){}

    T* address(T &x){
        return static_cast<T*>(&x);
    }
    const T* address(const T &x){
        return static_cast<const T*>(&x);
    }

    T* allocate(size_t _n,const void* hit=0 ){
        return static_cast<T*>(::operator new(_n*sizeof(T)));
    }

    void deallocate(T* p, size_t _n){
        ::operator delete(p);
    }

    size_t max_size()const throw(){
        return static_cast<size_t>(std::numeric_limits<int>::max()/sizeof(T));
    }

    template<typename _Up, typename... _Args>
    void construct(_Up* __p, _Args&&... __args){
        ::new((void *)__p) _Up(std::forward<_Args>(__args)...);
    }

    template<typename _Up>
    void destroy(_Up* __p){
        __p->~_Up();
    }
};

template<typename T>
inline bool operator==(const SelfAlloc<T> &, const SelfAlloc<T> &){
    return true;
}

template<typename T>
inline bool operator!=(const SelfAlloc<T> &, const SelfAlloc<T> &){
    return false;
}

int main(int argc, char **argv){
    std::vector<int, SelfAlloc<int>> ewefwi; 
    ewefwi.push_back(2);
    ewefwi.push_back('a');
    auto wefwff = ewefwi;
    std::vector<int, SelfAlloc<int>> jlllll;
    jlllll = ewefwi;

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值