STL之内存管理
来源:互联网 发布:java supplier 编辑:程序博客网 时间:2024/06/14 00:18
STL的内存管理分为两级
第一个级别用于较大内存分配与释放的管理(>128byte), malloc_alloc
第二个级别用于小于128byte的内存管理,default_alloc
1 mallloc_alloc实现
它直接采用c语言中的malloc, realloc和free实现
源码如下
<span style="font-size:14px;">template <int __inst>class __malloc_alloc_template {private: static void* _S_oom_malloc(size_t); static void* _S_oom_realloc(void*, size_t);#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG static void (* __malloc_alloc_oom_handler)();#endifpublic: static void* allocate(size_t __n) { void* __result = malloc(__n); if (0 == __result) __result = _S_oom_malloc(__n); return __result; } static void deallocate(void* __p, size_t /* __n */) { free(__p); } static void* reallocate(void* __p, size_t /* old_sz */, size_t __new_sz) { void* __result = realloc(__p, __new_sz); if (0 == __result) __result = _S_oom_realloc(__p, __new_sz); return __result; } static void (* __set_malloc_handler(void (*__f)()))() { void (* __old)() = __malloc_alloc_oom_handler; __malloc_alloc_oom_handler = __f; return(__old); }};</span>
2 default_alloc实现
这是系统默认的内存管理器
它内部维护着一个大小为16的free_list数组,用于管理8, 16, 24, ..., 128共16个不同大小的空间.
相同大小的空间都以链表方式组织.这部分空间故且称之为"自由空间".
同时,它还维护着一个"堆空间",通过以下变量
static char* _S_start_free;//堆空间开始位置
static char* _S_end_free;//结束位置
static size_t _S_heap_size;//大小
模板源码:
<span style="font-size:14px;">template <bool threads, int inst>class __default_alloc_template {private: // Really we should use static const int x = N // instead of enum { x = N }, but few compilers accept the former.# ifndef __SUNPRO_CC enum {_ALIGN = 8}; enum {_MAX_BYTES = 128}; enum {_NFREELISTS = 16}; // _MAX_BYTES/_ALIGN# endif static size_t _S_round_up(size_t __bytes) { return (((__bytes) + (size_t) _ALIGN-1) & ~((size_t) _ALIGN - 1)); }__PRIVATE: union _Obj { union _Obj* _M_free_list_link; char _M_client_data[1]; /* The client sees this. */ };private:# ifdef __SUNPRO_CC static _Obj* __STL_VOLATILE _S_free_list[]; // Specifying a size results in duplicate def for 4.1# else static _Obj* __STL_VOLATILE _S_free_list[_NFREELISTS]; # endif static size_t _S_freelist_index(size_t __bytes) {//从0开始 return (((__bytes) + (size_t)_ALIGN-1)/(size_t)_ALIGN - 1); } // Returns an object of size __n, and optionally adds to size __n free list. static void* _S_refill(size_t __n); // Allocates a chunk for nobjs of size size. nobjs may be reduced // if it is inconvenient to allocate the requested number. static char* _S_chunk_alloc(size_t __size, int& __nobjs); // Chunk allocation state. static char* _S_start_free; static char* _S_end_free; static size_t _S_heap_size;# ifdef __STL_THREADS static _STL_mutex_lock _S_node_allocator_lock;# endif // It would be nice to use _STL_auto_lock here. But we // don't need the NULL check. And we do need a test whether // threads have actually been started. class _Lock; friend class _Lock; class _Lock { public: _Lock() { __NODE_ALLOCATOR_LOCK; } ~_Lock() { __NODE_ALLOCATOR_UNLOCK; } };public:/** * 1) n > 128-------> 一级配置器 malloc * 2) 获取n对应的free_list槽位,不是空分配一个并调整剩余空间 * 3) 若为空,调整n到8的整数倍, 调用refill获取新的空间, * 如果refill返回保证会有可用空间,为上层提供可靠服务 */ /* __n must be > 0 */ static void* allocate(size_t __n) { void* __ret = 0; if (__n > (size_t) _MAX_BYTES) { __ret = malloc_alloc::allocate(__n); } else { _Obj* __STL_VOLATILE* __my_free_list = _S_free_list + _S_freelist_index(__n); // Acquire the lock here with a constructor call. // This ensures that it is released in exit or during stack // unwinding.# ifndef _NOTHREADS /*REFERENCED*/ _Lock __lock_instance;# endif _Obj* __RESTRICT __result = *__my_free_list; if (__result == 0) __ret = _S_refill(_S_round_up(__n)); else { *__my_free_list = __result -> _M_free_list_link; __ret = __result; } } return __ret; }; /* __p may not be 0 */ static void deallocate(void* __p, size_t __n) { if (__n > (size_t) _MAX_BYTES) malloc_alloc::deallocate(__p, __n); else { _Obj* __STL_VOLATILE* __my_free_list = _S_free_list + _S_freelist_index(__n); _Obj* __q = (_Obj*)__p; // acquire lock# ifndef _NOTHREADS /*REFERENCED*/ _Lock __lock_instance;# endif /* _NOTHREADS */ __q -> _M_free_list_link = *__my_free_list; *__my_free_list = __q; // lock is released here } } static void* reallocate(void* __p, size_t __old_sz, size_t __new_sz);} ;</span>
内存布局图:
下面重点介绍下内存分配的过程
1) allocate 上面已有介绍
/**
* 1) n > 128-------> 一级配置器 malloc
* 2) 获取n对应的free_list槽位,不是空分配一个并调整剩余空间
* 3) 若为空,调整n到8的整数倍, 调用refill获取新的空间,
* 如果refill返回保证会有可用空间,为上层提供可靠服务
*/
2) refill
<span style="font-size:14px;">/* * 1) 以20倍原大小, 先调用chunk_alloc, 如果空间足够会预先获取空间备用. * 2) chunk_alloc成功返回,保证至少有一个可用空间 * 3) 如果可用空间仅一个, 直接返回 * 4) 多余一个, 取出第一个用作返回,其他剩余添加到响应的free_list槽位 */template <bool __threads, int __inst>void*__default_alloc_template<__threads, __inst>::_S_refill(size_t __n){ int __nobjs = 20; char* __chunk = _S_chunk_alloc(__n, __nobjs); _Obj* __STL_VOLATILE* __my_free_list; _Obj* __result; _Obj* __current_obj; _Obj* __next_obj; int __i; if (1 == __nobjs) return(__chunk); __my_free_list = _S_free_list + _S_freelist_index(__n); /* Build free list in chunk */ __result = (_Obj*)__chunk; *__my_free_list = __next_obj = (_Obj*)(__chunk + __n); for (__i = 1; ; __i++) { __current_obj = __next_obj; __next_obj = (_Obj*)((char*)__next_obj + __n); if (__nobjs - 1 == __i) { __current_obj -> _M_free_list_link = 0; break; } else { __current_obj -> _M_free_list_link = __next_obj; } } return(__result);}</span>
3) chunk_alloc
<span style="font-size:14px;">/** * 1) 计算要获取的最大总空间total_bytes,以及剩余空间bytes_left * 2) 如果total_bytes > bytes_left, 直接分配返回 * 3) 若干至少能满足一个,即bytes_left >= __size, 分配最大可分配空间,并返回 *上述两种是从内存池中获取空间. * 4) 若还不能满足,只能向heap空间求助.分配一个2 * total_bytes + _S_round_up(_S_heap_size >> 4) * 更大的空间,bytes_to_get * 5) 现将内存池中剩余的小空间加到相应的free_list槽位 * 6) 向heap索要bytes_to_get空间, * 成功则增大内存池空间,这时的内存池能够满足要求了,在调用chunk_alloc进行新一轮分配,并返回 * 7) 若失败, 则说明heap空间不够,于是转向free_list中比size大的槽位, * 查找能够一个可用的节点. * 8) 若找到这样的节点,以它作为内存池空间,调用chunk_alloc进行新一轮分配,并返回 * 9) 若free_list不存在这样的节点,则求助与一级分配器 * (char*)malloc_alloc::allocate(__bytes_to_get); * 一级分配器在内存不足时,会回调用相应的处理函数去榨取空间,若失败,默认为抛异常或终止程序. * 这个处理过程可以由客户定义自己的行为. * */template <bool __threads, int __inst>char*__default_alloc_template<__threads, __inst>::_S_chunk_alloc(size_t __size, int& __nobjs){ char* __result; size_t __total_bytes = __size * __nobjs; size_t __bytes_left = _S_end_free - _S_start_free; if (__bytes_left >= __total_bytes) { __result = _S_start_free; _S_start_free += __total_bytes; return(__result); } else if (__bytes_left >= __size) { __nobjs = (int)(__bytes_left/__size); __total_bytes = __size * __nobjs; __result = _S_start_free; _S_start_free += __total_bytes; return(__result); } else { size_t __bytes_to_get = 2 * __total_bytes + _S_round_up(_S_heap_size >> 4); // Try to make use of the left-over piece. if (__bytes_left > 0) { _Obj* __STL_VOLATILE* __my_free_list = _S_free_list + _S_freelist_index(__bytes_left); ((_Obj*)_S_start_free) -> _M_free_list_link = *__my_free_list; *__my_free_list = (_Obj*)_S_start_free; } _S_start_free = (char*)malloc(__bytes_to_get); if (0 == _S_start_free) { size_t __i; _Obj* __STL_VOLATILE* __my_free_list; _Obj* __p; // Try to make do with what we have. That can't // hurt. We do not try smaller requests, since that tends // to result in disaster on multi-process machines. for (__i = __size; __i <= (size_t) _MAX_BYTES; __i += (size_t) _ALIGN) { __my_free_list = _S_free_list + _S_freelist_index(__i); __p = *__my_free_list; if (0 != __p) { *__my_free_list = __p -> _M_free_list_link; _S_start_free = (char*)__p; _S_end_free = _S_start_free + __i; return(_S_chunk_alloc(__size, __nobjs)); // Any leftover piece will eventually make it to the // right free list. } } _S_end_free = 0;// In case of exception. _S_start_free = (char*)malloc_alloc::allocate(__bytes_to_get); // This should either throw an // exception or remedy the situation. Thus we assume it // succeeded. } _S_heap_size += __bytes_to_get; _S_end_free = _S_start_free + __bytes_to_get; return(_S_chunk_alloc(__size, __nobjs)); }}</span>
3 对外提供的简单接口
<span style="font-size:14px;">template<class _Tp, class _Alloc>class simple_alloc {public: static _Tp* allocate(size_t __n) { return 0 == __n ? 0 : (_Tp*) _Alloc::allocate(__n * sizeof (_Tp)); } static _Tp* allocate(void) { return (_Tp*) _Alloc::allocate(sizeof (_Tp)); } static void deallocate(_Tp* __p, size_t __n) { if (0 != __n) _Alloc::deallocate(__p, __n * sizeof (_Tp)); } static void deallocate(_Tp* __p) { _Alloc::deallocate(__p, sizeof (_Tp)); }};</span>
0 0
- STL之内存管理
- STL设计思想之内存管理
- STL之内存处理
- 操作系统之内存管理
- Android之内存管理
- OC之内存管理
- cocos2dx 之内存管理
- c++之内存管理
- OC之内存管理
- jvm之内存管理
- 操作系统之内存管理
- 简单之内存管理
- OC之内存管理
- cocos2dx 之内存管理
- Android之内存管理
- OC之内存管理
- OC之内存管理
- 虚拟机之内存管理
- 理解C++ dynamic_cast
- 七月二号
- 破解TexturePacker加密资源 —— 使用IDA
- springMVC学习笔记-jsr303使用
- c++强制类型转换:dynamic_cast、const_cast 、static_cast、reinterpret_cast
- STL之内存管理
- libjpeg学习4:libjpeg-turbo之YUV
- 求二叉树中节点的最大距离
- android 手机屏幕密度归一化方案
- mini2440第一课《汇编点亮LED》
- 【Linux 内核网络协议栈源码剖析】accept 函数剖析
- jQuery基础入门第一弹
- 开始玩hadoop12--hbase设计和解决方案
- 78.对学生成绩进行排序