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. FoxPro 打开文件及使用SQL查询

    set exclusive off OPEN DATABASE t:\tpswin\comp1\time.dbc SHARED select empl_no,date,in, bout, bin, o ...

  2. 更改Eclipse里的Classpath Variables M2_REPO

    M2_REPO这个classpath  variable 是不能改变的. 为什么 Eclipse 里的 Classpath Variables M2_REPO 无法修改(non modifiable) ...

  3. 迷你MVVM框架 avalonjs 沉思录 第2节 DOM操作的三大问题

    jQuery之所以击败Prototype.js,是因为它自一开始就了解这三大问题,并提出完善的解决方案. 第一个问题,DOM什么时候可用.JS不像C那样有一个main函数,里面的逻辑不分主次.但JS是 ...

  4. linux img文件 分区挂载

    首先是将制作的img文件比如hd5.img和loop设备建立联系. losetup /dev/loop0 hd5.img 然后用fdisk分区:fdisk /dev/loop0 mkfs.ext4 / ...

  5. java.lang.VerifyError: Inconsistent stackmap frames at branch target 81

    java项目中有如下代码: @RequestMapping(value = "/getMxList") @ResponseBody public Map<String, Ob ...

  6. viewer.js--一个强大的jQuery图像查看插件

    Viewer 是一款强大的 jQuery 图像浏览插件. 主要功能: 支持选项 支持方法 支持事件 支持触摸 支持移动 支持缩放 支持旋转 支持键盘 跨浏览器支持 查看演示      立即下载 部分插 ...

  7. 如何去掉UItableview headerview黏性

    有时候使用UITableView所实现的列表,会使用到header view,但是又不希望它粘在最顶上而是跟随滚动而消失或者出现,下面的代码片段就是实现此功能 sectionHeaderHeight ...

  8. C#重启IIS

    using System.Diagnostics; using System.ServiceProcess; //ServiceController sc1 = new ServiceControll ...

  9. C语言日志处理

    一.简介 zlog是一个高可靠性.高性能.线程安全.灵活.概念清晰的纯C日志函数库,在效率.功能.安全性上大大超过了log4c,并且是用c写成的,具有比较好的通用性. 二.安装 下载 https:// ...

  10. 从YouTube改版看“移动优先”——8个移动优先网站设计案例赏析

    2011年,Luke Wroblewski大神提出了移动优先的设计理念.在当时看来这无疑是一个打破行业常规的新型设计原则.而在移动互联网大行其道的今天,谁遵守移动优先的设计理念,设计出最好的移动端网站 ...