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
本文来自博客园,作者:XDU18清欢,转载请注明原文链接:https://www.cnblogs.com/XDU-mzb/p/14849837.html