STL空间配置器的强大和借鉴作用不言而喻,查阅资料,发现了Dawn_sf已经对其有了极其深入和详细的描述,所以决定偷下懒借用其内容,只提供自己实现STL空间配置器的源码,具体解析内容参考:
(一)STL — 浅析一级空间配置器
(二)STL — 浅析二级空间配置器

1. 一级空间配置器实现

1.1 接口

  1. // 完全解析STL空间配置器
  2. /***** 一级配置区 ****************************/
  3. // 1. 采用mallo/relloc/free申请和释放内存
  4. // 2. 处理内存申请失败的处理
  5. // (1)设置set_new_handle,若为NULL抛出__THROW_BAD_ALLOC;
  6. // (2)尝试重复申请
  7. /**********************************************/
  8. #pragma once
  9.  
  10. class CFirstLevelAlloc;
  11. class CSecondLevelAlloc;
  12.  
  13. #ifdef _CHUNK_ALLOC
  14. typedef CFirstLevelAlloc SelfAlloc;
  15. #else
  16. typedef CSecondLevelAlloc SelfAlloc;
  17. #endif
  18.  
  19. typedef void(*CallBackFunc)();
  20. class CFirstLevelAlloc
  21. {
  22. public:
  23. CFirstLevelAlloc();
  24.  
  25. static CallBackFunc m_CallBackFunc;
  26. static void* Allocate(size_t nSize);
  27. static void* Allocate(void *p, size_t nSize);
  28. static void Deallocate(void *p, size_t nSize = );
  29. static void SetCallBackHandle(CallBackFunc cb);
  30.  
  31. private:
  32. static void* ReAllocate(size_t nSize);
  33. static void* ReAllocate(void *p, size_t nSize);
  34. };
  35.  
  36. enum {ALIGN = }; // 小型区块的上调边界
  37. enum {MAX_BYTES = }; // 小型区块的上限
  38. enum {FREELISTNUM = MAX_BYTES/ALIGN}; // free-lists个数
  39.  
  40. // 空闲内存链表结构
  41. union FreeList
  42. {
  43. union FreeList *pFreeList;
  44. char client_data[];
  45. };

1.2 实现

  1. #include "stdio.h"
  2. #include "alloc_define.h"
  3. #include <stdlib.h>
  4. #include <iostream>
  5. using namespace std;
  6.  
  7. CallBackFunc CFirstLevelAlloc::m_CallBackFunc = NULL;
  8. CFirstLevelAlloc::CFirstLevelAlloc()
  9. {
  10.  
  11. }
  12.  
  13. void* CFirstLevelAlloc::Allocate(size_t nSize)
  14. {
  15. void *result = malloc(nSize);
  16. if (NULL == result)
  17. {
  18. result = ReAllocate(nSize);
  19. }
  20. return result;
  21. }
  22.  
  23. void* CFirstLevelAlloc::Allocate(void *p, size_t nSize)
  24. {
  25. void *result = realloc(p, nSize);
  26. if (NULL == result)
  27. {
  28. result = ReAllocate(p, nSize);
  29. }
  30. return result;
  31. }
  32.  
  33. void* CFirstLevelAlloc::ReAllocate(size_t nSize)
  34. {
  35. while ()
  36. {
  37. if (NULL == m_CallBackFunc)
  38. {
  39. cout << "bad alloc!" << endl;
  40. return NULL;
  41. }
  42. else
  43. {
  44. m_CallBackFunc();
  45. void *result = Allocate(nSize);
  46. if (result)
  47. {
  48. return result;
  49. }
  50. }
  51. }
  52. }
  53.  
  54. void* CFirstLevelAlloc::ReAllocate(void *p, size_t nSize)
  55. {
  56. while ()
  57. {
  58. if (NULL == m_CallBackFunc)
  59. {
  60. cout << "bad alloc!" << endl;
  61. return NULL;
  62. }
  63. else
  64. {
  65. m_CallBackFunc();
  66. void *result = Allocate(p, nSize);
  67. if (result)
  68. {
  69. return result;
  70. }
  71. }
  72. }
  73. }
  74.  
  75. void CFirstLevelAlloc::Deallocate(void *p, size_t nSize)
  76. {
  77. free(p);
  78. }
  79. void CFirstLevelAlloc::SetCallBackHandle(CallBackFunc cb)
  80. {
  81. m_CallBackFunc = cb;
  82. }

2. 二级空间配置器实现

2.1 接口

  1. class CSecondLevelAlloc
  2. {
  3. public:
  4. CSecondLevelAlloc();
  5. static void* Allocate(size_t nSize);
  6. static void Deallocate(void *p, size_t nSize);
  7. static void SetCallBackHandle(CallBackFunc cb);
  8.  
  9. private:
  10. static size_t FreeListIndex(int nBytes); // 根据区块大小得到freelist索引
  11. static size_t Round_Up(int nBytes); // 将bytes按内存对齐上调至ALIGN的倍数
  12. static char *ChunkAlloc(size_t nSize, int& nObjs);
  13. static void* Refill(size_t nSize);
  14.  
  15. private:
  16. static FreeList *m_pFreeList[FREELISTNUM];
  17. static char *m_pStartFree;
  18. static char *m_pEndFree;
  19. static size_t m_nHeapSize;
  20. };

2.2 实现

  1. FreeList* CSecondLevelAlloc::m_pFreeList[FREELISTNUM] = { };
  2. char* CSecondLevelAlloc::m_pStartFree = NULL;
  3. char* CSecondLevelAlloc::m_pEndFree = NULL;
  4. size_t CSecondLevelAlloc::m_nHeapSize = ;
  5. CSecondLevelAlloc::CSecondLevelAlloc()
  6. {
  7. }
  8.  
  9. void* CSecondLevelAlloc::Allocate(size_t nSize)
  10. {
  11. // 首先判断nSize,若大于128则调用一级配置器,否则调用二级配置器
  12. if (nSize > (size_t)MAX_BYTES)
  13. {
  14. cout << "调用1级配置器配置内存空间,空间大小:" << nSize << endl;
  15. return (CFirstLevelAlloc::Allocate(nSize));
  16. }
  17.  
  18. cout << "调用2级配置器配置内存空间,空间大小:" << nSize << endl;
  19. FreeList **pFreeList = m_pFreeList + FreeListIndex(nSize);
  20. if (*pFreeList == NULL)
  21. {
  22. return Refill(Round_Up(nSize));
  23. }
  24.  
  25. FreeList *p = *pFreeList;
  26. *pFreeList = p->pFreeList;
  27. return p;
  28. }
  29.  
  30. void CSecondLevelAlloc::Deallocate(void *p, size_t nSize)
  31. {
  32. // 首先判断nSize,若大于128则调用一级配置器,否则调用二级配置器
  33. if (nSize > MAX_BYTES)
  34. {
  35. cout << "调用1级配置器释放内存空间,空间大小:" << nSize << endl;
  36. return CFirstLevelAlloc::Deallocate(p);
  37.  
  38. }
  39.  
  40. cout << "调用2级配置器释放内存空间,空间大小:" << nSize << endl;
  41. FreeList **pFreeList = m_pFreeList + FreeListIndex(Round_Up(nSize));
  42. ((FreeList*)p)->pFreeList = *pFreeList;
  43. *pFreeList = (FreeList*)p;
  44. }
  45. size_t CSecondLevelAlloc::FreeListIndex(int nBytes)
  46. {
  47. return ((nBytes + ALIGN) / ALIGN - );
  48. }
  49. size_t CSecondLevelAlloc::Round_Up(int nBytes)
  50. {
  51. return ((nBytes + ALIGN - ) & (~(ALIGN - )));
  52. }
  53. char* CSecondLevelAlloc::ChunkAlloc(size_t nSize, int& nObjs)
  54. {
  55. char *pResult = NULL;
  56. size_t nTotalBytes = nSize * nObjs;
  57. size_t nBytesLeft = m_pEndFree - m_pStartFree;
  58. if (nBytesLeft >= nTotalBytes)
  59. {
  60. // 内存池剩余空间完全满足需求量
  61. pResult = m_pStartFree;
  62. m_pStartFree += nTotalBytes;
  63. return pResult;
  64. }
  65. else if (nBytesLeft >= nSize)
  66. {
  67. // 内存池剩余空间不能完全满足需求量,但足够供应一个或一个以上的区块
  68. nObjs = nBytesLeft / nSize;
  69. pResult = m_pStartFree;
  70. m_pStartFree += (nObjs * nSize);
  71. return pResult;
  72. }
  73. else
  74. {
  75. // 内存池剩余空间连一个区块的大小都无法提供,就调用malloc申请内存,新申请的空间是需求量的两倍
  76. // 与随着配置次数增加的附加量,在申请之前,将内存池的残余内存回收
  77. size_t nBytesToGet = * nTotalBytes + Round_Up(m_nHeapSize >> );
  78. // 以下试着让内存池中的残余零头还有价值
  79. if (nBytesLeft > )
  80. {
  81. // 内存池内还有一些零头,先配给适当的freelist
  82. // 首先寻找适当的freelist
  83. FreeList *pFreeList = m_pFreeList[FreeListIndex(nBytesLeft)];
  84. // 调整freelist,将内存池中的残余空间编入
  85. ((FreeList*)m_pStartFree)->pFreeList = pFreeList;
  86. pFreeList = (FreeList*)m_pStartFree;
  87.  
  88. }
  89. // 配置heap空间
  90. m_pStartFree = (char *)malloc(nBytesToGet);
  91. if (NULL == m_pStartFree)
  92. {
  93. //如果没有申请成功,如果free_list当中有比n大的内存块,这个时候将free_list中的内存块释放出来.
  94. //然后将这些内存编入自己的free_list的下标当中.调整nobjs.
  95. int i;
  96. FreeList **pFreeList, *p;
  97. for (i = nSize; i < MAX_BYTES; i += ALIGN)
  98. {
  99. pFreeList = m_pFreeList+FreeListIndex(i);
  100. p = *pFreeList;
  101. if (NULL != p)
  102. {
  103. // freelist内尚有未用区块
  104. // 调整freelist以释放未用区块
  105. *pFreeList = p->pFreeList;
  106. m_pStartFree = (char *)p;
  107. m_pEndFree = m_pStartFree + i;
  108. // 调整自己,为了修正nobjs
  109. return (ChunkAlloc(nSize, nObjs));
  110. }
  111. }
  112.  
  113. m_pEndFree = NULL; // 如果出现意外(山穷水尽,到处都没有内存可用)
  114. // 调用1级配置器,看out-of-range机制能不能出点力
  115. m_pStartFree = (char*)CFirstLevelAlloc::Allocate(nBytesToGet);
  116. }
  117.  
  118. m_nHeapSize += nBytesToGet;
  119. m_pEndFree = m_pStartFree + nBytesToGet;
  120. return (ChunkAlloc(nSize, nObjs));
  121. }
  122. }
  123.  
  124. // 当freelist中没有可用的区块了时,就调用ReFill重新填充空间
  125. // 新的空间将取自内存池,缺省为20个新节点
  126. // 但万一内存池空间不足,获得的节点数可能小于20
  127. void* CSecondLevelAlloc::Refill(size_t nSize)
  128. {
  129. int nObjs = ; // 默认每个链表组右20个区块
  130. char *pChunk = ChunkAlloc(nSize, nObjs);
  131. if ( == nObjs)
  132. {
  133. // 如果获得一个区块,这个区块就分配给调用者,freelist无新节点
  134. return pChunk;
  135. }
  136.  
  137. // 若有多余的区块,则将其添加到对应索引的freelist中
  138. FreeList **pFreeList = m_pFreeList + FreeListIndex(nSize);
  139. FreeList *pResult = (FreeList *)pChunk; // 这一块准备返回给客户端
  140.  
  141. FreeList *pCurrent = NULL;
  142. FreeList *pNext = NULL;
  143. *pFreeList = pNext = (FreeList*)(pChunk + nSize);
  144. for (int i = ; i < nObjs; i++)
  145. {
  146. pCurrent = pNext;
  147. pNext = (FreeList*)((int)pNext + nSize);
  148. pCurrent->pFreeList = pNext;
  149. }
  150. pCurrent->pFreeList = NULL;
  151.  
  152. return pResult;
  153. }
  154.  
  155. void CSecondLevelAlloc::SetCallBackHandle(CallBackFunc cb)
  156. {
  157. CFirstLevelAlloc::m_CallBackFunc = cb;
  158. }

3. 配置器标准接口

  1. #pragma once
  2.  
  3. #include "alloc_define.h"
  4. template<typename T, typename Alloc = SelfAlloc>
  5. class CSimpleAlloc
  6. {
  7. public:
  8. static T* Allocate(size_t n)
  9. {
  10. if (n == )
  11. {
  12. return NULL;
  13. }
  14. return (T *)Alloc::Allocate(n * sizeof(T));
  15. }
  16.  
  17. static T* Allocate(void)
  18. {
  19. return (T *)Alloc::Allocate(sizeof(T));
  20. }
  21.  
  22. static void Deallocate(T *p, size_t n)
  23. {
  24. if (n != )
  25. {
  26. Alloc::Deallocate(p, n * sizeof(T));
  27. }
  28. }
  29.  
  30. static void Deallocate(T *p)
  31. {
  32. Alloc::Deallocate(p, sizeof(T));
  33. }
  34.  
  35. static void SetCallBackHandle(CallBackFunc cb)
  36. {
  37. Alloc::SetCallBackHandle(cb);
  38. }
  39. };

4. 测试

  1. #include "stdio.h"
  2.  
  3. #include<iostream>
  4. using namespace std;
  5.  
  6. #include"stl_test.h"
  7. #include "simple_alloc.h"
  8. #include<vector>
  9.  
  10. void Func()
  11. {
  12. cout << "调用回调函数处理内存不足的情况" << endl;
  13. // 为了防止死循环,该函数应该加上一个判断条件如果它本次没有清理出空间,那么就抛出异常
  14. }
  15.  
  16. template <class T, class Alloc = SelfAlloc>
  17. class A
  18. {
  19. public:
  20. A() :m_ptr(NULL), m_nSize(){}
  21. A(size_t nSize)
  22. {
  23. DataAllocator::SetCallBackHandle(Func);
  24. m_nSize = nSize;
  25. m_ptr = DataAllocator::Allocate(nSize);
  26. for (int i = ; i < (int)nSize; i++)
  27. {
  28. m_ptr[i] = i;
  29. cout << m_ptr[i] << " ";
  30. }
  31. cout << endl;
  32. }
  33. ~A()
  34. {
  35. DataAllocator::Deallocate(m_ptr, m_nSize);
  36. }
  37.  
  38. private:
  39. T *m_ptr;
  40. size_t m_nSize;
  41. typedef CSimpleAlloc<T, Alloc> DataAllocator;
  42. };
  43. void main()
  44. {
  45. A<int> a();
  46. A<int> b();
  47. a.~A();
  48. b.~A();
  49. }

STL空间配置器解析和实现的更多相关文章

  1. 【转】STL空间配置器

    STL空间配置器(allocator)在所有容器内部默默工作,负责空间的配置和回收.STL标准为空间配置器定义了标准接口(可见<STL源码剖析>P43).而具体实现细节则由各编译器实现版本 ...

  2. STL空间配置器那点事

    STL简介 STL(Standard Template Library,标准模板库),从根本上说,STL是一些“容器”的集合,这些“容器”有list,vector,set,map等,STL也是算法和其 ...

  3. stl空间配置器线程安全问题补充

    摘要 在上一篇博客<STL空间配置器那点事>简单介绍了空间配置器的基本实现 两级空间配置器处理,一级相关细节问题,同时简单描述了STL各组件之间的关系以及设计到的设计模式等. 在最后,又关 ...

  4. STL空间配置器

    1.什么是空间配置器? 空间配置器负责空间配置与管理.配置器是一个实现了动态空间配置.空间管理.空间释放的class template.以内存池方式实现小块内存管理分配.关于内存池概念可以点击:内存池 ...

  5. 咬碎STL空间配置器

    STL空间配置器 一.开场白: 给我的感觉就是,了解是空间配置器的功能,是那么的明了:在看原理,我还是很开心:接下来是360度大转变: 那么长的变量或者函数命名.那么多的宏.不爽,不过,遇上我这种二货 ...

  6. 【陪你系列】5 千字长文+ 30 张图解 | 陪你手撕 STL 空间配置器源码

    大家好,我是小贺. 点赞再看,养成习惯 文章每周持续更新,可以微信搜索「herongwei」第一时间阅读和催更,本文 GitHub https://github.com/rongweihe/MoreT ...

  7. STL——空间配置器(构造和析构基本工具)

    以STL的运用角度而言,空间配置器是最不需要介绍的东西,它总是隐藏在一切组件(更具体地说是指容器,container)的背后,默默工作,默默付出.但若以STL的实现角度而言,第一个需要介绍的就是空间配 ...

  8. STL空间配置器、vector、list、deque、map复习

    本文写于2017-03-03,从老账号迁移到本账号,原文地址:https://www.cnblogs.com/huangweiyang/p/6440830.html STL的六大组件:容器.算法.迭代 ...

  9. STL——空间配置器(SGI-STL)

    一. 空间配置器标准接口 参见<STL源码剖析>第二章-2.1.<memory>文件. 二.具备次配置力的SGI空间配置器 1. SGI STL的配置器与众不同,也与标准规范不 ...

随机推荐

  1. 大道至简(第五i章)读后感

    大道至简(第五章)读后感 再一次在不想看的情况下读大道至简第五章,一个项目的实现中,“过程”与“工程”是同一个概念吗?答案自然是否定的.“过程”是一个确定的模板,而“工程”是有一个目的的实现在里面. ...

  2. python 课堂笔记-for语句

    for i in range(10): print("----------",i) for j in range(10): print("world",j) i ...

  3. 给二维码(图片)添加文字(水印),让生成的二维码中间带logo

    <?php //生成二维码 require_once IA_ROOT . '/framework/library/qrcode/phpqrcode.php'; QRcode::png($url, ...

  4. TIJ读书笔记02-控制执行流程

      TIJ读书笔记02-控制执行流程 TIJ读书笔记02-控制执行流程 if-else 迭代 无条件分支 switch语句 所有条件语句都是以条件表达式的真假来决定执行路径,也就是通过布尔测试结果来决 ...

  5. 2018.7.12训练赛 -K

    水题 判断素数 因为范围是到16位,所以可以用long long存储 然后判断是否为素数就ok了. 但我提交之后显示10个测试样例通过了9个.......原因是下面标红的部分. 埃氏筛法:若a是合数, ...

  6. linux 安装tomcat7

    wget http://mirror.bit.edu.cn/apache/tomcat/tomcat-7/v7.0.81/bin/apache-tomcat-7.0.81.tar.gz 解压安装包 t ...

  7. linux设置系统时间与时区以及设置bios时间同步系统时间

    有装过Linux系统的人,可能都会有这样的经历,就是该机器安装windows系统时,时间正确,但是安装了linux系统后,尽管时区选择正确,也会发现系统时间不对.这是由于安装系统时采用了UTC,那么什 ...

  8. Freemarker中大于号>的使用

    在Freemarker中,比较数据的大小时候,要注意大于号(>)的使用.如果不注意,程序就会发生异常信息,如下面的例子:   1 2 3 4 <#assign x = 4> < ...

  9. freemarker日志实现过程分析

    freemarker有自己的log类,这是一个抽象类,具体的日志打印委托给classpath里面合适的日志jar包来执行,寻找合适日志jar的查找顺序是:Apache Log4J, Apache Av ...

  10. 测试人员git常用命令

    首先要到git官网下载一个gitbash,并安装. https://git-scm.com/ 1. 配置git key $ ssh-keygen -t rsa 按3个回车,密码为空,在目录C:\Use ...