前言

上一节只分析了第二级配置器是由多个链表来存放相同内存大小, 当没有空间的时候就向内存池索取就行了, 却没有具体分析内存池是怎么保存空间的, 是不是内存池真的有用不完的内存, 本节我们就具体来分析一下

内存池

static data template的初始化

template <bool threads, int inst>
char *__default_alloc_template<threads, inst>::start_free = 0; // 内存池的首地址
template <bool threads, int inst>
char *__default_alloc_template<threads, inst>::end_free = 0; // 内存池的结束地址
template <bool threads, int inst>
size_t __default_alloc_template<threads, inst>::heap_size = 0; // 多次调用内存池, 就会更多的是给链表分配内存, 这就是一个增量.

这里代码注释写的很清楚了, 我就提取出来分析一下吧

  1. 内存池的大小大于需要的空间, 直接返回起始地址(nobjs默认设置为20, 所以每次调用都会给链表额外的19个内存块)
  2. 内存池的内存不足以马上分配那么多内存, 但是还能满足分配一个即以上的大小, 那就全部分配出去
  3. 如果一个对象的大小都已经提供不了了, 先将零碎的内存块给一个小内存的链表来保存, 然后就准备调用malloc申请40块+额外大小的内存块(额外内存块就由heap_size决定), 如果申请失败跳转到步骤4, 成功跳转到步骤6
  4. 充分利用更大内存的链表, 通过递归来调用他们的内存块
  5. 如果还是没有内存块, 直接调用一级配置器来申请内存, 还是失败就抛出异常, 成功申请就继续执行
  6. 重新修改内存起始地址和结束地址为当前申请的地址块, 重新调用chunk_alloc分配内存
// 内存池
template <bool threads, int inst>
char* __default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs)
{
char * result;
size_t total_bytes = size * nobjs; // 链表需要申请的内存大小
size_t bytes_left = end_free - start_free; // 内存池里面总共还有多少内存空间 // 内存池的大小大于需要的空间, 直接返回起始地址
if (bytes_left >= total_bytes)
{
result = start_free;
start_free += total_bytes; // 内存池的首地址往后移
return(result);
}
// 内存池的内存不足以马上分配那么多内存, 但是还能满足分配一个即以上的大小, 那就按对齐方式全部分配出去
else if (bytes_left >= size)
{
nobjs = bytes_left/size;
total_bytes = size * nobjs;
result = start_free;
start_free += total_bytes; // 内存池的首地址往后移
return(result);
}
else
{
// 如果一个对象的大小都已经提供不了了, 那就准备调用malloc申请两倍+额外大小的内存
size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
// Try to make use of the left-over piece.
// 内存池还剩下的零头内存分给给其他能利用的链表, 也就是绝不浪费一点.
if (bytes_left > 0)
{
// 链表指向申请内存的地址
obj * __VOLATILE * my_free_list = free_list + FREELIST_INDEX(bytes_left);
((obj *)start_free) -> free_list_link = *my_free_list;
*my_free_list = (obj *)start_free;
}
start_free = (char *)malloc(bytes_to_get);
// 内存不足了
if (0 == start_free)
{
int i;
obj * __VOLATILE * my_free_list, *p;
// 充分利用剩余链表的内存, 通过递归来申请
for (i = size; i <= __MAX_BYTES; i += __ALIGN)
{
my_free_list = free_list + FREELIST_INDEX(i);
p = *my_free_list;
if (0 != p)
{
*my_free_list = p -> free_list_link;
start_free = (char *)p;
end_free = start_free + i;
return(chunk_alloc(size, nobjs));
}
}
// 如果一点内存都没有了的话, 就只有调用一级配置器来申请内存了, 并且用户没有设置处理例程就抛出异常
end_free = 0; // In case of exception.
start_free = (char *)malloc_alloc::allocate(bytes_to_get);
}
// 申请内存成功后重新修改内存起始地址和结束地址, 重新调用chunk_alloc分配内存
heap_size += bytes_to_get;
end_free = start_free + bytes_to_get;
return(chunk_alloc(size, nobjs));
}
}

总结

内存池的存在就是为了能快速的提供我们做需要的内存并且保存多余的空间, 让STL分配空间不再每次都进行malloc和free的操作, 效率又很有保障. 有时用户申请的块更小, 我们也能充分的利用起来. 唯一可能不足的是我们每次只申请char个大小, 但是内存池获得的确是8字节的大小.

最新文章

  1. [转]向facebook学习,通过协程实现mysql查询的异步化
  2. sql server系统表详细说明
  3. oj上java大数的使用
  4. mac上的键盘生活——输入法键位设置小技巧以及去掉自带输入法
  5. 对exp full 和 imp full的认识
  6. Hello Bolg!
  7. 单片微机原理P4:80C51串口与串行总线拓展
  8. C#代码启用事务锁Transaction进行一系列提交回滚操作
  9. 【一天一道LeetCode】#349. Intersection of Two Arrays
  10. Unity UGUI基础之Slider、Scrollbar
  11. SpringBoot配置日志logback
  12. 关于表单元素的name及HTML中的id
  13. 常用的web服务器软件整理(win+linux)
  14. 《Java大学教程》—第14章 抽象、继承和接口
  15. WEB服务器----Apache 安装配置
  16. 步步为营-62-Excel的导入和导出
  17. List去重问题
  18. js变量按照存储方式区分,有哪些类型,并表述其特点
  19. chrome浏览器快捷键大全
  20. Python 爬虫入门实例(爬取小米应用商店的top应用apk)

热门文章

  1. mysql 存储引擎的选择你会吗?
  2. 基于二叉搜索树的符号表和BST排序
  3. Linux下CMake使用介绍
  4. Java知识总结---整合SpringMVC+Mybatis+Spring(二)
  5. android 获取屏幕的高度和宽度、获取控件在屏幕中的位置、获取屏幕中控件的高度和宽度
  6. raid5什么意思?如何做raid5?raid5 几块硬盘?
  7. 使用adb进行关机(转载)
  8. [Swift通天遁地]二、表格表单-(7)电子邮件Mail:实现单元格左右滑动调出功能按钮
  9. Akka源码分析-Actor发消息
  10. 网络简要&lt;入门篇&gt;