STL_内存池

推荐资料

《STL源码剖析》
STL 内存池 https://blog.csdn.net/xy913741894/article/details/66974004#

为什么内存池不用平衡树实现,而用链表实现

时间换空间,每申请一块内存都需要一定的“税”,联合实现的链表可以最低幅度的消耗空间
平衡树、线段树都可以快速的实现动态内存分配
xdoj,线段树处理内存分配 https://acm.xidian.edu.cn/problem.php?id=1065

c++中allocator的说明

就是把内存申请/释放,对象构造/析构,两部分拆开到allocator里面
对象构造/析构,用type_traits的技巧进行优化...熟模板元的话,这个其实很简单
这片文章主要分析如何高效的实现一个能融入STL的allocator
重点在于,如何高效的分配、释放内存
这里仿照SGI_STL的实现,也就是侯杰《STL源码剖析》中的实现
当申请空间长度 > 128,调用malloca/free封装的第一级内存池
当申请空间长度 <= 128,调用链表维护的二级内存池

std::allocator 的标准接口

以下是书中给出的一个最简单的allocator实现,它是符合STL标准的

#include <vector>
using ll = long long int;

#include <new>
#include <cstddef>
#include <cstdlib>
#include <climits>
#include <iostream>
namespace my_alloc
{
    // allocate的实际实现,简单封装new,当无法获得内存时,报错并退出
    using namespace std; 
    template <class T>
    inline T* _allocate(ptrdiff_t size, T*) {
        set_new_handler(0);
        T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));
        if (tmp == 0) {
            cerr << "out of memory" << endl;
            exit(1);
        }
        return tmp;
    }

    // deallocate的实际实现,简单封装delete
    template <class T>
    inline void _deallocate(T* buffer) { ::operator delete(buffer); }

    // construct的实际实现,直接调用对象的构造函数
    template <class T1, class T2>
    inline void _construct(T1* p, const T2& value) { new(p) T1(value); }

    // destroy的实际实现,直接调用对象的析构函数
    template <class T>
    inline void _destroy(T* ptr) { ptr->~T(); }

    template <class T>
    class allocator {
    public:
        typedef T           value_type;
        typedef T*          pointer;
        typedef const T*    const_pointer;
        typedef T&          reference;
        typedef const T&    const_reference;
        typedef size_t      size_type;
        typedef ptrdiff_t   difference_type;

        // 构造函数
        allocator(){ return; }
        template <class U>
        allocator(const allocator<U>& c){}

        // rebind allocator of type U
        template <class U>
        struct rebind { typedef allocator<U> other; };

        // allocate,deallocate,construct和destroy函数均调用上面的实际实现
        // hint used for locality. ref.[Austern],p189
        pointer allocate(size_type n, const void* hint = 0) {
            return _allocate((difference_type)n, (pointer)0);
        }
        void deallocate(pointer p, size_type n) { _deallocate(p); }
        void construct(pointer p, const T& value) { _construct(p, value); }
        void destroy(pointer p) { _destroy(p); }

        pointer address(reference x) { return (pointer)&x; }
        const_pointer const_address(const_reference x) { return (const_pointer)&x; }

        size_type max_size() const
		  {
		    return size_type(UINT64_MAX / sizeof(T)); 
		  }   
    };
}

int main()
  {
  	std::vector<ll,my_alloc::allocator<ll>> v;
  	for (ll i = 0;i < 10000000;i++)
  	  v.push_back(i);
  	std::cout << v[10000] << " " << v.size() << " " << v.capacity() << std::endl;
	return 0;
  }

迷惑的地方

1.内存池工作期间的内存只会增长,不释放给操作系统。直到内存池销毁的时候,才把所有的 block delete 掉
block之间依旧用单链表串起来即可
2.实现分两部分 : 内存池 + 16个自由链表
归还、申请单个节点给自由链表,仅仅在单链表头处操作即可
3.那么,在归还单个节点的时候,如何知道该节点的大小?
这个是接口要求的 void deallocate(pointer p, size_type n)就可以知晓应该归还给哪一个list
4.为什么所使用的obj会有client_data[1],很奇怪

union obj
  {
    union obj * free_list_link;
    char client_date[1];  
};

这个博文说的很清楚,client_data[1]就是为了取地址,省略了static_cast<char>(&obj)的麻烦
妙哇,union实现简化版本的static_cast,并且void
+ 10和char* + 10的地址一样
https://blog.csdn.net/LaoJiu_/article/details/77601205

posted @ 2021-06-04 15:35  XDU18清欢  阅读(112)  评论(0编辑  收藏  举报