前言

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

内存池

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字节的大小.

STL源码分析之内存池的更多相关文章

  1. leveldb源码分析之内存池Arena

    转自:http://luodw.cc/2015/10/15/leveldb-04/ 这篇博客主要讲解下leveldb内存池,内存池很多地方都有用到,像linux内核也有个内存池.内存池的存在主要就是减 ...

  2. STL源码分析读书笔记--第二章--空间配置器(allocator)

    声明:侯捷先生的STL源码剖析第二章个人感觉讲得蛮乱的,而且跟第三章有关,建议看完第三章再看第二章,网上有人上传了一篇读书笔记,觉得这个读书笔记的内容和编排还不错,我的这篇总结基本就延续了该读书笔记的 ...

  3. STL源码分析《3》----辅助空间不足时,如何进行归并排序

    两个连在一起的序列 [first, middle) 和 [middle, last) 都已经排序, 归并排序最核心的算法就是 将 [first, middle) 和 [middle, last) 在  ...

  4. netty源码分析 - Recycler 对象池的设计

    目录 一.为什么需要对象池 二.使用姿势 2.1 同线程创建回收对象 2.2 异线程创建回收对象 三.数据结构 3.1 物理数据结构图 3.2 逻辑数据结构图(重要) 四.源码分析 4.2.同线程获取 ...

  5. v76.01 鸿蒙内核源码分析(共享内存) | 进程间最快通讯方式 | 百篇博客分析OpenHarmony源码

    百篇博客分析|本篇为:(共享内存篇) | 进程间最快通讯方式 进程通讯相关篇为: v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志 v27.05 鸿蒙内核源码分析(互斥锁) | 同样 ...

  6. STL源码分析《4》----Traits技术

    在 STL 源码中,到处可见 Traits 的身影,其实 Traits 不是一种语法,更确切地说是一种技术. STL库中,有一个函数叫做 advance, 用来将某个迭代器(具有指针行为的一种 cla ...

  7. STL 源码分析《1》---- list 归并排序的 迭代版本, 神奇的 STL list sort

    最近在看 侯捷的 STL源码分析,发现了以下的这个list 排序算法,乍眼看去,实在难以看出它是归并排序. 平常大家写归并排序,通常写的是 递归版本..为了效率的考虑,STL库 给出了如下的 归并排序 ...

  8. Memcached源码分析之内存管理

    先再说明一下,我本次分析的memcached版本是1.4.20,有些旧的版本关于内存管理的机制和数据结构与1.4.20有一定的差异(本文中会提到). 一)模型分析在开始解剖memcached关于内存管 ...

  9. stl源码分析之allocator

    allocator封装了stl标准程序库的内存管理系统,标准库的string,容器,算法和部分iostream都是通过allocator分配和释放内存的.标准库的组件有一个参数指定使用的allocat ...

随机推荐

  1. Android获取全部存储卡挂载路径

    近期因项目需求.须要在存储卡查找文件,经測试发现部分手机挂载路径查找不到,这里分享一个有效的方法. /** * 获取全部存储卡挂载路径 * @return */ public static List& ...

  2. POJ 3468 A Simple Problem with Integers(线段树区间更新)

    题目地址:POJ 3468 打了个篮球回来果然神经有点冲动. . 无脑的狂交了8次WA..竟然是更新的时候把r-l写成了l-r... 这题就是区间更新裸题. 区间更新就是加一个lazy标记,延迟标记, ...

  3. Server Tomcat v8.0 Server at localhost failed to start.

    怎么办? 查资料的话别人会告诉你须要删除一个东西.这是一种方法.可是你的错误并不是通过这种方法能够解决. 比方像我 <url-pattern>login</url-pattern&g ...

  4. linux 磁盘性能监控

    linux下对于查看进程的命令非常多也非常强大.经常使用的如:ps  top 可是在磁盘性能监控方面就没有那么统一了. 以下列举一些磁盘监控命令.此处仅仅是起到抛砖引玉作用,具体使用參数请參考man手 ...

  5. leetcode 217 Contains Duplicate 数组中是否有反复的数字

     Contains Duplicate Total Accepted: 26477 Total Submissions: 73478 My Submissions Given an array o ...

  6. java使用poi读取doc和docx文件(maven自动导入依赖包)

    java使用poi读取doc和docx文件(maven自动导入依赖包) 于是在网上搜寻了一阵之后才发现原来doc文档和excel一样不能用普通的io流的方法来读取,而是也需要用poi,于是进行了一番尝 ...

  7. uoj#34

    模板 #include<bits/stdc++.h> #define pi acos(-1) using namespace std; ; int n, m, L, x; int r[N] ...

  8. oracle基础学习---------1

    1.SQL执行时间的开关 set timing on --->开         set timing off--->关 2.创建数据表.以已存在的表创建(也就是复制一个表.但表内没有数据 ...

  9. 洛谷P1341 无序字母对(欧拉回路)

    P1341 无序字母对 题目描述 给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒).请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现. 输入输出格式 ...

  10. Tyvj1305最大子序和(单调队列优化dp)

    描述 输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大. 例如 1,-3,5,1,-2,3 当m=4时,S=5+1-2+3=7当m=2或m=3时,S=5+1=6 输入 ...