class __default_alloc_template {
enum { unit = 8 };//分配单位 后面直接用8代替
enum { max_bytes = 128 };//最大分配字节数 后面直接用128代替
enum { list_size = 16 }; //数组大小 后面直接用16代替 static char* _S_start_free;//目前内存池的首地址
static char* _S_end_free;//目前内存池的尾地址
static size_t _S_heap_size;//内存池的总大小,包括分配和未分配的 union obj
{
union obj* next_obj;//指向下一个内存的地址
char _M_client_data[1];//内存的首地址
}; static obj* _S_free_list[16];//链表数组 static size_t _S_round_up(size_t __bytes)//向上取整 8的倍数
{
return (((__bytes)+(size_t)8 - 1) & ~((size_t)8 - 1));
} static size_t _S_freelist_index(size_t __bytes) //根据字节数找到对应的链表数组下标(字节数向上取整8的倍数)
{
return (((__bytes)+(size_t)8 - 1) / (size_t)8 - 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. class _Lock;//保证线程安全的。构造时加锁,析构时释放
friend class _Lock;
class _Lock
{
public:
_Lock() { __NODE_ALLOCATOR_LOCK; }
~_Lock() { __NODE_ALLOCATOR_UNLOCK; }
}; static void* allocate(size_t __n)
{
void* __ret = 0;//返回的内存地址
if (__n > (size_t)128) //如果请求内存大于128b,则调用第一级配置器
{
__ret = malloc_alloc::allocate(__n);
}
else
{
// 根据请求内存大小,找到链表数组负责这个大小的索引位置的地址
obj** __my_free_list =
_S_free_list //链表数组首地址
+ _S_freelist_index(__n);//偏移量(n会向上取整8倍数) _Lock __lock_instance;//加锁 obj* __RESTRICT __result = *__my_free_list;//取得对应链表的第一块内存 if (__result == 0)//这个链表不够内存时,调用_S_refill重新从内存池分配
{
__ret = _S_refill(_S_round_up(__n));
}
else
{
*__my_free_list = __result->next_obj;//指向该链表的下一块内存
__ret = __result;
}
}
return __ret;
}; static void deallocate(void* __p, size_t __n)//释放内存块
{
if (__n > (size_t)128)//大于128b,调用第一级配置器回收
{
malloc_alloc::deallocate(__p, __n);
}
else {
obj** __my_free_list//找到对应的链表
= _S_free_list + _S_freelist_index(__n);
obj* __q = (obj*)__p; _Lock __lock_instance;//加锁 __q->next_obj = *__my_free_list;//回收的内存的下一块内存指向原链表的第一块内存 *__my_free_list = __q;//链表第一块内存指向被回收的内存
}
} }; char* __default_alloc_template::_S_chunk_alloc(size_t __size, int& __nobjs)
{
char* __result;
size_t __total_bytes = __size * __nobjs;//__total_bytes为从内存池上要取得内存块总大小。__nobjs默认为20,但会受条件限制而改变
size_t __bytes_left = _S_end_free - _S_start_free;//_S_end_free - _S_start_free得到目前内存池剩余的内存 if (__bytes_left >= __total_bytes) //如果足够20个直接取
{
__result = _S_start_free;
_S_start_free += __total_bytes;
return(__result);
}
else if (__bytes_left >= __size) //如果不够20个且大于1个,则能取多少个就取多少个
{
__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 = 40 * __size + _S_round_up(_S_heap_size >> 4);//从内存里面要得到的内存大小,至少40块 if (__bytes_left > 0) //把内存池剩余的内存分配到对应的链表中,清空当前内存池,以便后续去处理不连续的内存池里的另一块内存块
{
obj** __my_free_list = _S_free_list + _S_freelist_index(__bytes_left);
((obj*)_S_start_free)->next_obj = *__my_free_list;
*__my_free_list = (obj*)_S_start_free;
}
_S_start_free = (char*)malloc(__bytes_to_get);//调用malloc从内存分配
if (0 == _S_start_free) //系统内存不足时
{
size_t __i;
obj** __my_free_list;
obj* __p; for (__i = __size; __i <= (size_t)128;__i += (size_t)8) // 利用好自己拥有的内存,即从其他空闲链表获取内存.
{
__my_free_list = _S_free_list + _S_freelist_index(__i);
__p = *__my_free_list;
if (0 != __p) {
*__my_free_list = __p->next_obj;
_S_start_free = (char*)__p;
_S_end_free = _S_start_free + __i;
return(_S_chunk_alloc(__size, __nobjs));//此时调用调用chunk_alloc,就能获取得到足够的内存
}
}
_S_end_free = 0; // 从其他链表也没获取到内存
_S_start_free = (char*)malloc_alloc::allocate(__bytes_to_get); // 调用第一级配置器,因为有错误处理函数,也是最后的补救办法了
}
_S_heap_size += __bytes_to_get;//当从系统分配到内存时,更新到目前为止的内存总数
_S_end_free = _S_start_free + __bytes_to_get;
return(_S_chunk_alloc(__size, __nobjs));//递归调用说不定成功了呢
}
} void* __default_alloc_template::_S_refill(size_t __n)
{
int __nobjs = 20;//默认分配20块内存块
char* __chunk = _S_chunk_alloc(__n, __nobjs);//从内存池获取,返回第一块
obj** __my_free_list;
obj* __result;
obj* __currentobj;
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++) {//串联起来
__currentobj = __next_obj;
__next_obj = (obj*)((char*)__next_obj + __n);
if (__nobjs - 1 == __i) {
__currentobj->next_obj = 0;//最后一块的next为空
break;
}
else {
__currentobj->next_obj = __next_obj;
}
}
return(__result);
}

  

sgi stl内存池实现------源码加翻译的更多相关文章

  1. SGI STL内存配置器存在内存泄漏吗?

    阅读了SGI的源码后对STL很是膜拜,很高质量的源码,从中学到了很多.温故而知新!下文中所有STL如无特殊说明均指SGI版本实现. STL 内存配置器 STL对内存管理最核心部分我觉得是其将C++对象 ...

  2. linux线程池thrmgr源码解析

    linux线程池thrmgr源码解析 1         thrmgr线程池的作用 thrmgr线程池的作用是提高程序的并发处理能力,在多CPU的服务器上运行程序,可以并发执行多个任务. 2      ...

  3. C#共享内存实例 附源码

    原文 C#共享内存实例 附源码 网上有C#共享内存类,不过功能太简单了,并且写内存每次都从开头写.故对此进行了改进,并做了个小例子,供需要的人参考. 主要改进点: 通过利用共享内存的一部分空间(以下称 ...

  4. java线程池ThreadPoolExector源码分析

    java线程池ThreadPoolExector源码分析 今天研究了下ThreadPoolExector源码,大致上总结了以下几点跟大家分享下: 一.ThreadPoolExector几个主要变量 先 ...

  5. C++技术问题总结-第8篇 STL内存池是怎么实现的

    STL内存池机制,使用双层级配置器.第一级採用malloc.free,第二级视情况採用不同策略. 这样的机制从heap中要空间,能够解决内存碎片问题. 1.内存申请流程图     简要流程图例如以下. ...

  6. 线程池ThreadPoolExecutor源码解读研究(JDK1.8)

    一.什么是线程池 为什么要使用线程池?在多线程并发开发中,线程的数量较多,且每个线程执行一定的时间后就结束了,下一个线程任务到来还需要重新创建线程,这样线程数量特别庞大的时候,频繁的创建线程和销毁线程 ...

  7. Spring源码加载过程图解(一)

    最近看了一下Spring源码加载的简装版本,为了更好的理解,所以在绘图的基础上,进行了一些总结.(图画是为了理解和便于记忆Spring架构) Spring的核心是IOC(控制反转)和AOP(面向切面编 ...

  8. 深入浅出Java线程池:源码篇

    前言 在上一篇文章深入浅出Java线程池:理论篇中,已经介绍了什么是线程池以及基本的使用.(本来写作的思路是使用篇,但经网友建议后,感觉改为理论篇会更加合适).本文则深入线程池的源码,主要是介绍Thr ...

  9. Java并发包源码学习系列:线程池ScheduledThreadPoolExecutor源码解析

    目录 ScheduledThreadPoolExecutor概述 类图结构 ScheduledExecutorService ScheduledFutureTask FutureTask schedu ...

随机推荐

  1. 496. Next Greater Element I + 503. Next Greater Element II + 556. Next Greater Element III

    ▶ 给定一个数组与它的一个子列,对于数组中的一个元素,定义它右边第一个比他大的元素称为他的后继,求所给子列的后继构成的数组 ▶ 第 496 题,规定数组最后一个元素即数组最大元素的后继均为 -1 ● ...

  2. Spring Boot SSO单点登入

    https://github.com/ITDragonBlog/daydayup/tree/master/SpringBoot-SSO 流程图: 1: Redis 保存用户信息 到Redis(KEY- ...

  3. EL 和 JSTL

    EL 什么是EL表达式 EL(Express Lanuage) 表达式可以嵌入在jsp页面内部 减少jsp脚本的编写 EL出现的目的是要替代jsp页面中脚本的编写 作用区间 EL最主要的作用是获取四大 ...

  4. win7局域网内共享文件夹及安全设置

    右键想要共享的文件夹,选择属性. 在文件夹属性对话框中选择共享标签,如图: 点击共享按钮,弹出文件共享对话框. 添加 Everyone ,并根据实际需要修改权限.权限可以是读取 或 读取/写入. 到此 ...

  5. 73. Set Matrix Zeroes (Array)

    Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place. Follow ...

  6. 118. Pascal's Triangle (Array)

    Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5, Retu ...

  7. 四种常见的 POST 提交数据方式,使用postman会用到

    http://www.aikaiyuan.com/6324.html 用postman时候,选错了就出不来结果.用postman选择 application/x-www-form-urlencoded

  8. PHP语言性能优化——少使用魔术方法

    对以下使用魔术方法和不适用魔术方法运行时间进行比较 使用魔术方法test1.php: <?php /** * 测试类 */ class test { private $name = " ...

  9. 数据挖掘算法以及其实现zz

    实验一    分类技术及其应用 实习要求: 基于线性回归模型拟合一个班学生的学习成绩,建立预测模型.数据可由自己建立100个学生的学习成绩. 1)    算法思想: 最小二乘法 设经验方程是y=F(x ...

  10. clone一行div tr 每次增量赋值

    $("#add_tan").click(function () { num++; $("tbody tr.tab_xue").eq(0).clone(true) ...