背景

软件开发过程中,我们总是频繁的使用一些小块的内存,进行类型的定义,对象内存的动态申请或释放。这个过程很容易产生内存碎片。为此stl设计时采用了享元模式进行内存管理,通过开辟一小块让空间配置器进行管理,从而解决这些问题。

stl空间配置器的实现策略

内存空间大小为128字节,用户申请空间如果小于128,就使用空间配置器管理。多于128,就使用malloc,free进行处理

空间配置器的实现机制

内存池+自由链表

为了便于管理,空间配置器在分配的时候都是以8的倍数对齐,只需要管理128内存区间的16个自由链表节点就行,但这样实际依旧会有内存碎片产生,比如7/8,9/16;

重点 chunk_alloc

这部分代码比较难读,我也没有完全理解,不过这部分注意就是对内存池的管理,压榨内存池,开辟空间给自由链表,当内存池剩余的内存无法满足链表区块,就malloc

代码

我读的是开源项目TinySTL的代码,个人感觉可读性非常棒

#ifndef _ALLOC_H_
#define _ALLOC_H_#include <cstdlib>namespace TinySTL{/***空间配置器*/class alloc{private:enum EAlign{ ALIGN = 8};//小型区块的上调边界enum EMaxBytes{ MAXBYTES = 128};//小型区块的上限,超过的区块由malloc分配enum ENFreeLists{ NFREELISTS = (EMaxBytes::MAXBYTES / EAlign::ALIGN)};//free-lists的个数enum ENObjs{ NOBJS = 20};//每次增加的节点数private://free-lists的节点构造union obj{union obj *next;char client[1];};static obj *free_list[ENFreeLists::NFREELISTS];private:static char *start_free;//内存池起始位置static char *end_free;//内存池结束位置static size_t heap_size;//private://将bytes上调至8的倍数static size_t ROUND_UP(size_t bytes){return ((bytes + EAlign::ALIGN - 1) & ~(EAlign::ALIGN - 1));}//根据区块大小,决定使用第n号free-list,n从0开始计算static size_t FREELIST_INDEX(size_t bytes){return (((bytes)+EAlign::ALIGN - 1) / EAlign::ALIGN - 1);}//返回一个大小为n的对象,并可能加入大小为n的其他区块到free-liststatic void *refill(size_t n);//配置一大块空间,可容纳nobjs个大小为size的区块//如果配置nobjs个区块有所不便,nobjs可能会降低static char *chunk_alloc(size_t size, size_t& nobjs);public:static void *allocate(size_t bytes);static void deallocate(void *ptr, size_t bytes);static void *reallocate(void *ptr, size_t old_sz, size_t new_sz);};char *alloc::start_free = 0;char *alloc::end_free = 0;size_t alloc::heap_size = 0;alloc::obj *alloc::free_list[alloc::ENFreeLists::NFREELISTS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};void *alloc::allocate(size_t bytes){if (bytes > EMaxBytes::MAXBYTES){return malloc(bytes);}size_t index = FREELIST_INDEX(bytes);obj *list = free_list[index];if (list){//此list还有空间给我们free_list[index] = list->next;return list;}else{//此list没有足够的空间,需要从内存池里面取空间return refill(ROUND_UP(bytes));}}void alloc::deallocate(void *ptr, size_t bytes){if (bytes > EMaxBytes::MAXBYTES){free(ptr);}size_t index = FREELIST_INDEX(bytes);obj *node = static_cast<obj *>(ptr);node->next = free_list[index];free_list[index] = node;}void *alloc::reallocate(void *ptr, size_t old_sz, size_t new_sz){deallocate(ptr, old_sz);ptr = allocate(new_sz);return ptr;}//返回一个大小为n的对象,并且有时候会为适当的free list增加节点//假设bytes已经上调为8的倍数void *alloc::refill(size_t bytes){size_t nobjs = ENObjs::NOBJS;//从内存池里取char *chunk = chunk_alloc(bytes, nobjs);obj **my_free_list = 0;obj *result = 0;obj *current_obj = 0, *next_obj = 0;if (nobjs == 1){//取出的空间只够一个对象使用return chunk;}else{my_free_list = free_list + FREELIST_INDEX(bytes);result = (obj *)(chunk);*my_free_list = next_obj = (obj *)(chunk + bytes);//将取出的多余的空间加入到相应的free list里面去for (int i = 1;; ++i){current_obj = next_obj;next_obj = (obj *)((char *)next_obj + bytes);if (nobjs - 1 == i){current_obj->next = 0;break;}else{current_obj->next = next_obj;}}return result;}}//假设bytes已经上调为8的倍数char *alloc::chunk_alloc(size_t bytes, size_t& nobjs){char *result = 0;size_t total_bytes = bytes * nobjs;size_t bytes_left = end_free - start_free;if (bytes_left >= total_bytes){//内存池剩余空间完全满足需要result = start_free;start_free = start_free + total_bytes;return result;}else if(bytes_left >= bytes){//内存池剩余空间不能完全满足需要,但足够供应一个或以上的区块nobjs = bytes_left / bytes;total_bytes = nobjs * bytes;result = start_free;start_free += total_bytes;return result;}else{//内存池剩余空间连一个区块的大小都无法提供size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);if(bytes_left > 0){obj **my_free_list = free_list + FREELIST_INDEX(bytes_left);((obj *)start_free)->next = *my_free_list;*my_free_list = (obj *)start_free;}start_free = (char *)malloc(bytes_to_get);if (!start_free){obj **my_free_list = 0, *p = 0;for(int i = 0; i <= EMaxBytes::MAXBYTES; i += EAlign::ALIGN){my_free_list = free_list + FREELIST_INDEX(i);p = *my_free_list;if(!p){*my_free_list = p->next;start_free = (char *)p;end_free = start_free + i;return chunk_alloc(bytes, nobjs);}}end_free = 0;}heap_size += bytes_to_get;end_free = start_free + bytes_to_get;return chunk_alloc(bytes, nobjs);}}
}#endif

c++ stl源码-我理解的空间配置器相关推荐

  1. C++ STL(第三篇:空间配置器)

    1.概述 以STL运用的角度而言,空间配置器是最不需要介绍的,它总是藏在一切组件的背后,默默工作.整个STL的操作对象都存放在容器之中(vertor.list),而容器一定需要配置空间以放置资料,这就 ...

  2. malloc开辟的空间在哪一个区间_C++进阶系列之STL(2)SGI版本空间配置器

    1.STL中的空间配置器在STL中,空间配置器分了2组,分别为一级空间配置器和二级空间配置器,但是它们都有自己各自运用的场合:一般说来,一级空间配置器一般分配的空间大于128B,二级空间配置器的分配空 ...

  3. STL源码剖析 第八章 配接器

    设计模式:将一个类的接口转化为另外一个类的接口 配接器的概观和分类 改变仿函数接口  函数配接器  :queue和stack 通过修饰deque函数接口来实现 改变容器接口      容器配接器  : ...

  4. STL源码剖析 空间配置器 查漏补缺

    ptrdiff_t含义 减去两个指针的结果的带符号整数类型 ptrdiff_t (Type support) - C 中文开发手册 - 开发者手册 - 云+社区 - 腾讯云 std::set_new_ ...

  5. stl源码剖析_《STL源码剖析》学习笔记——空间配置器

    目录 1. 空间配置器概述 2. 构造和析构基本工具 3. 空间的配置与释放,std::alloc 4. 内存基本处理工具 1. 空间配置器概述 从STL的实现角度来看,空间配置器的位置尤为重要,整个 ...

  6. C++ STL : SGI-STL空间配置器源码剖析

    文章目录 空间配置器的概念 SGI-STL空间配置器 一级空间配置器 二级空间配置器 申请空间 补充内存块 从内存池中索要空间 空间回收 内存碎片 外碎片 内碎片 空间配置器的再次封装 空间配置器的概 ...

  7. STL 源码剖析 空间配置器

    以STL的运用角度而言,空间配置器是最不需要介绍的东西,它总是隐藏在一切组件(更具体地说是指容器,container) 的背后 但是STL的操作对象都存放在容器的内部,容器离不开内存空间的分配 为什么 ...

  8. STL笔记(二)---空间配置器

    一.概述 allocator是STL的六大组件之一,空间配置器.其作用就是为各个容器管理内存(内存开辟 内存回收).allocator配置的对象不只是内存,它也可以向硬盘索取空间.使用STL库的时候不 ...

  9. STL空间配置器(二)

    ***上一篇是对STL空间配置器的入门级理解,在这一篇中,我将讨论更加深入的SGI STL空间适配器的内容.在下一节中,我将根据自己的理解,结合STL标准接口,实现一个符合STL标准的具有次级配置能力 ...

  10. 【STL】STL空间配置器

    STL标准规格告诉我们,STL配置器定义于<memory>中,而SGI的<memory>中含有两个文件. #include<stl_alloc.h> //内存空间的 ...

最新文章

  1. GPU加速:宽深度推理
  2. Qt编写网络调试助手(TCP客户端+TCP服务端+UDP服务端)终极版开源
  3. BCH开发Cashscript语言,可构建自主决策交易特定方案
  4. 富文本编辑器Quill(二)上传图片与视频
  5. Java中的occur_time,PLSQL报错: ORA-12170:TNS connect timeout occurred
  6. Linux运行级详解
  7. linux安装openssl
  8. ibm aix_IBM AIX:Java进程大小监视
  9. 【X264系列】之命令参数解析
  10. .NetCore中EFCore for MySql整理(二)
  11. 通俗易懂机器人运动学左乘右乘理解
  12. rtc校准算法_CRC校验算法的实例解析
  13. [Docker入门-2] Docker Containers 的创建和使用
  14. 使用shopnc发送qq邮件遇到的坑
  15. 快速学习-常见DOS命令精讲
  16. springboot 2.X jdbc 实现session共享mysql
  17. Ubuntu apt安装包 dev、dbg、utils后缀的含义
  18. SHARC库函数cfft_mag详解
  19. OpenCV:07图像轮廓
  20. android MediaPlayer 源码分析 1

热门文章

  1. Intel CPU性能linpack测试
  2. 计算机网络对等网实验报告,计算机网络实验报告_双机互联
  3. 求职经历,三轮技术面 +HR 面,面试也不过如此
  4. 【计算机网络】(一):计算机网络+互联网基本知识
  5. Unity 关于Toggle的ison默认没有显示监听结果的解决
  6. 【软件工程/系统软件/程序设计语言】 2019年-中国计算机学会推荐国际学术会议和期刊目录(四)
  7. java毕业设计——基于java+JSP+MySQL的健身俱乐部会员管理系统设计与实现(毕业论文+程序源码)——健身俱乐部会员管理系统
  8. 笔记本电脑已连接WIFI密码查看方法
  9. 百度2017春招笔试真题编程题集合--买帽子
  10. Erphp loggedin 异地IP登录自动禁封用户 WordPress插件