stl中的空间配置器
2016-01-22 23:33
316 查看
一般我们习惯的c++内存配置如下
这里的new实际上分为两部分执行。首先是先用::operator new配置内存,然后执行Foo::Foo()构造对象内容。delete也一样,先运行Foo::~Foo()析构对象,再用::operator delete释放内存。在SGI STL中,这两部分分别在<stl_alloc.h>和<stl_construct.h>中。本文讲的便是<stl_alloc.h>中的故事。
SGI STL中将配置器分为两级。第一级直接用malloc和free管理内存,第二级则使用内存池以避免内存碎片。这两级都由simple_alloc包装起来以符合stl标准。如图
default_alloc.cpp
class Foo { ... }; Foo* pf = new Foo; delete pf;
这里的new实际上分为两部分执行。首先是先用::operator new配置内存,然后执行Foo::Foo()构造对象内容。delete也一样,先运行Foo::~Foo()析构对象,再用::operator delete释放内存。在SGI STL中,这两部分分别在<stl_alloc.h>和<stl_construct.h>中。本文讲的便是<stl_alloc.h>中的故事。
SGI STL中将配置器分为两级。第一级直接用malloc和free管理内存,第二级则使用内存池以避免内存碎片。这两级都由simple_alloc包装起来以符合stl标准。如图
#include "default_alloc.h" #include "malloc_alloc.h" using namespace Chenstl; default_alloc::obj *default_alloc::free_list[NFREELISTS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; char *default_alloc::start_free = 0; //内存池的起始位置 char *default_alloc::end_free = 0; //内存池的终止位置 size_t default_alloc::heap_size = 0; void *default_alloc::allocate(size_t n) { obj *result = 0; obj **my_free_list = 0; if (n > MAX_BYTES) return malloc_alloc::allocate(n); //寻找free lists中合适的一个 my_free_list = free_list + FREELIST_INDEX(n); result = *my_free_list; if(0 == result) {//没有找到可用的freelist,从内存池里取出空间 return refill(ROUND_UP(n)); } //调整freelist *my_free_list = result->next; return result; } void default_alloc::deallocate(void *p, size_t n) { } //返回一个大小为n的对象,并可能加入大小为n的其他区块到freelist //在ANSI c中,void *不允许进行加减操作,所以chunk用char * void *default_alloc::refill(size_t n) { int objs = 20; char *chunk = chunk_alloc(n, objs); obj *next, *current; obj *result; obj **my_free_list; if (1 == objs) //只取出一个区块 return chunk; my_free_list = free_list + FREELIST_INDEX(n); result = (obj *)chunk; //这一块返回给客户端 //将freellist指向分配的区域 *my_free_list = next = (obj *)chunk + n; for (int i = 1;; i++) { current = next; next = (obj *)((char *)next + n); //这里注意不能直接用next+n if (i == objs - 1) { current->next = 0; break; } else current->next = next; } return result; } char *default_alloc::chunk_alloc(size_t size, int &nobjs) { char *result = 0; 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 = nobjs * size; 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) {//将内存池的零头分配给合适的freelist 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) {//系统堆内存不足,寻找还未使用的freelist obj *p = 0; obj **my_free_list = 0; for (int i = size; i < MAX_BYTES; ++i) { my_free_list = free_list + FREELIST_INDEX(i); p = *my_free_list; if (0 != p) {//还有未使用的freelist start_free = (char *)p; *my_free_list = p->next; end_free = start_free + i; //递归调用,修正nobjs return chunk_alloc(size, nobjs); } } //没内存可用,寄希望于第一级的new-handler或抛出异常 end_free = 0; start_free = (char *)malloc_alloc::allocate(bytes_to_get); } heap_size += bytes_to_get; end_free = start_free + bytes_to_get; return chunk_alloc(size, nobjs);//递归调用,修正nobjs } }
default_alloc.cpp
相关文章推荐
- Ace教你一步一步做Android新闻客户端(五) 优化Listview
- t持久化与集群部署开发详解
- [读书笔记]C#学习笔记七: C#4.0中微小改动-可选参数,泛型的可变性
- cvResize() 图像放缩
- 增加和删除用户组与用户
- 值得 Web 开发人员学习的20个 jQuery 实例教程
- codeforces 258B
- MAC 10.10.5编译opencv3.0(java版本)
- 三种弹窗的解析
- 蓝桥杯 日期计算
- coco2dx-js 实现 层拦截 点击响应事件
- Java集合(实现类线程安全性)
- php 获取自己的公网IP
- “请运行Chkdsk工具”怎么解决
- innerHTML和nnerText造成的乱码现象 以及 background-image放入.css中失效
- UVALive 4225 / HDU 2964 Prime Bases 贪心
- String、StringBuffer和StringBuilder类
- 1204 寻找子串位置
- codeforces 264B
- What are bitwise operators?