经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
STL源码分析之第二级配置器
来源:cnblogs  作者:倔强的铃铛  时间:2018/12/10 9:46:41  对本文有异议

前言

第一级是直接调用malloc分配空间, 调用free释放空间, 第二级三就是建立一个内存池, 小于128字节的申请都直接在内存池申请, 不直接调用mallocfree. 本节分析第二级空间配置器, STL将第二级配置器设置为默认的配置器, 所以只要一次申请的空间不超过128字节就默认在内存池中申请空间, 超过才会调用第一级配置器.

第二级配置器

首先先来介绍3个常量.

  1. __ALIGN : 以8字节进行对齐
  2. __MAX_BYTES : 二级分配器最大分配的内存大小
  3. __NFREELISTS : 128字节能分配的的链表个数, 并且从每个链表保存的内存大小都是8的倍数, 而且都比前一个大8字节, 也就是分别是8, 16, 32...128字节
  1. // 二级配置器
  2. enum {__ALIGN = 8}; // 设置对齐要求. 对齐为8字节, 没有8字节自动补齐
  3. enum {__MAX_BYTES = 128}; // 第二级配置器的最大一次性申请大小, 大于128就直接调用第一级配置器
  4. enum {__NFREELISTS = __MAX_BYTES/__ALIGN}; // 链表个数, 分别代表8, 16, 32....字节的链表

再介绍一个宏操作, 这是进行对齐操作, 将不满8的倍数的填充成8的倍数.

  1. static size_t FREELIST_INDEX(size_t bytes) { return (((bytes) + ALIGN-1) / __ALIGN - 1);}

从allocate先切入分析

  1. 先判断申请的字节大小是不是大于128字节, 是, 则交给第一级配置器来处理. 否, 继续往下执行
  2. 找到分配的地址对齐后分配的是第几个大小的链表.
  3. 获得该链表指向的首地址, 如果链表没有多余的内存, 就先填充链表.
  4. 返回链表的首地址, 和一块能容纳一个对象的内存, 并更新链表的首地址
  1. static void * allocate(size_t n)
  2. {
  3. obj * __VOLATILE * my_free_list;
  4. obj * __RESTRICT result;
  5. if (n > (size_t) __MAX_BYTES)
  6. {
  7. return(malloc_alloc::allocate(n));
  8. }
  9. my_free_list = free_list + FREELIST_INDEX(n);
  10. result = *my_free_list;
  11. if (result == 0) // 没有多余的内存, 就先填充链表.
  12. {
  13. void *r = refill(ROUND_UP(n));
  14. return r;
  15. }
  16. *my_free_list = result -> free_list_link;
  17. return (result);
  18. };

refill内存填充.

  1. 向内存池申请空间的起始地址
  2. 如果只申请到一个对象的大小, 就直接返回一个内存的大小, 如果有更多的内存, 就继续执行
  3. 从第二个块内存开始, 把从内存池里面分配的内存用链表给串起来, 并返回一个块内存的地址给用户
  1. // 内存填充
  2. template <bool threads, int inst>
  3. void* __default_alloc_template<threads, inst>::refill(size_t n)
  4. {
  5. int nobjs = 20;
  6. char * chunk = chunk_alloc(n, nobjs); // 向内存池申请空间的起始地址
  7. obj * __VOLATILE * my_free_list;
  8. obj * result;
  9. obj * current_obj, * next_obj;
  10. int i;
  11. // 如果只申请到一个对象的大小, 就直接返回一个内存的大小
  12. if (1 == nobjs) return(chunk);
  13. my_free_list = free_list + FREELIST_INDEX(n);
  14. // 申请的大小不只一个对象的大小的时候
  15. result = (obj *)chunk;
  16. // my_free_list指向内存池返回的地址的下一个对齐后的地址
  17. *my_free_list = next_obj = (obj *)(chunk + n);
  18. // 这里从第二个开始的原因主要是第一块地址返回给了用户, 现在需要把从内存池里面分配的内存用链表给串起来
  19. for (i = 1; ; i++)
  20. {
  21. current_obj = next_obj;
  22. next_obj = (obj *)((char *)next_obj + n);
  23. if (nobjs - 1 == i)
  24. {
  25. current_obj -> free_list_link = 0;
  26. break;
  27. }
  28. else
  29. {
  30. current_obj -> free_list_link = next_obj;
  31. }
  32. }
  33. return(result);
  34. }

再从deallocate结束

  1. 释放的内存大于128字节直接调用一级配置器进行释放
  2. 将内存直接还给对应大小的链表就行了, 并不用直接释放内存, 以便后面分配内存的时候快速.
  1. static void deallocate(void *p, size_t n)
  2. {
  3. obj *q = (obj *)p;
  4. obj * __VOLATILE * my_free_list;
  5. // 释放的内存大于128字节直接调用一级配置器进行释放
  6. if (n > (size_t) __MAX_BYTES)
  7. {
  8. malloc_alloc::deallocate(p, n);
  9. return;
  10. }
  11. my_free_list = free_list + FREELIST_INDEX(n);
  12. q -> free_list_link = *my_free_list;
  13. *my_free_list = q;
  14. }

统一的接口

定义符合STL规格的配置器接口, 不管是一级配置器还是二级配置器都是使用这个接口进行分配的

  1. // 定义符合STL规格的配置器接口, 不管是一级配置器还是二级配置器都是使用这个接口进行分配的
  2. template<class T, class Alloc>
  3. class simple_alloc {
  4. public:
  5. static T *allocate(size_t n)
  6. { return 0 == n? 0 : (T*) Alloc::allocate(n * sizeof (T)); }
  7. static T *allocate(void)
  8. { return (T*) Alloc::allocate(sizeof (T)); }
  9. static void deallocate(T *p, size_t n)
  10. { if (0 != n) Alloc::deallocate(p, n * sizeof (T)); }
  11. static void deallocate(T *p)
  12. { Alloc::deallocate(p, sizeof (T)); }
  13. };

总结

用链表来保存不同字节大小的内存块, 就很容易的进行维护, 而且每次的内存分配都直接可以从链表或者内存池中获得, 提升了我们申请内存的效率, 毕竟每次调用malloc和free效率是很低的, 特别是很小内存的时候.

STL默认的就是第二级配置器, 它会自动判断我们使用哪一个配置器.

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号