new运算包含两阶段操作:

1) 调用::operator new分配内存     2) 调用构造函数构造对象内容

delete运算包含两阶段操作:

1)调用析构函数将对象析构    2)调用::operator delete释放内存

stl内存配置操作由allocate()负责,内存释放操作由deallocate()负责;对象构造操作由construct()负责,对象析构操作由destroy()负责。

template <class T1, class T2>
inline void construct(T1 *p, const T2 &value) {
// placement new,将初值value设定到指针p所指的空间
new(p) T1(value);
} template <class T>
inline void destroy(T* pointer) {
// 显式的调用类的析构函数销毁对象,内存空间不会被释放
pointer->~T();
}

SGI设计了双层级配置器,第一级配置器__malloc_alloc_template直接使用malloc()和free(),第二级配置器__default_alloc_template视情况采用不同的策略:当配置区块超过128bytes时,调用第一级配置器,当配置区块小于128bytes时,采用内存池方式

//SGI第一级配置器
template<int inst>
class __malloc_alloc_template
{
private:
//处理内存不足的情况
//c++ new handler机制:系统在内存配置需求无法被满足时,调用一个指定函数,参见effective c++条款7
static void *oom_malloc(size_t);
static void *oom_realloc(void *, size_t);
static void(*__malloc_alloc_oom_handler)();//由用户设定,new_handler函数 public:
//第一级配置器直接使用malloc()
static void *allocate(size_t n)
{
void *result = malloc(n);
if (result == )
result = oom_malloc(n);
return result;
}
//第一级配置器直接使用free()
static void deallocate(void *p, size_t)
{
free(p);
}
//第一级配置器直接使用realloc
static void *reallocate(void *p, size_t, size_t new_sz)
{
void *result = realloc(p, new_sz);
if (result == )
result = oom_realloc(p, new_sz);
return result;
}
//仿真c++的set_new_handler()
static void(*set_malloc_handler(void(*f)()))()
{
void(*old) = __malloc_alloc_oom_handler;
__malloc_alloc_oom_handler = f;
return old;//恢复全局new_handler
}
};
//初值为0,由用户设定
template<int inst>
void(*__malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = ; template<int inst>
void *__malloc_alloc_template<inst>::oom_malloc(size_t n)
{
void(*my_malloc_handler());
void *result;
// 无限循环,尝试分配内存。先判断new_handler是否为空,若非空,调用new_handler,然后重新分配内存
for (;;)
{
my_malloc_handler = __malloc_alloc_oom_handler;
if ( == my_malloc_handler)
{
throw bad_alloc;
}
(*my_malloc_handler)();//尝试释放内存
result = malloc(n);//再次尝试配置内存
if (result)
return result;
}
} template<int inst>
void *__malloc_alloc_template<inst>::oom_realloc(void *p, size_t n)
{
void(*my_malloc_handler());
void *result;
//先设置处理例程,尝试释放内存,然后再次尝试分配内存
for (;;)
{
my_malloc_handler = __malloc_alloc_oom_handler;
if ( == my_malloc_handler)
{
throw bad_alloc;
}
(*my_malloc_handler)();//同上
result = realloc(p, n);
if (result)
return result;
}
} typedef __malloc_alloc_template<> malloc_alloc;

-


使用16个链表来维护大小不同的空闲内存块,分配小块内存时,从链表中划拨相应的块即可

enum{ __ALLGN =  };//小块的上调边界
enum{ __MAX_BYTES = };//小块的上限大小
enum{ __NFREELISTS = __MAX_BYTES / __ALLGN };//free_lists个数 //第二级空间配置器,threads判断是否用于多线程,第二参数无用
template<bool threads, int inst>
class __default_alloc_template
{
private:
//将请求内存大小上调至8的倍数,即将低三位加上7向高位进位,然后将低三位的余数变为0
static size_t ROUND_UP(size_t bytes)
{
return (((bytes)+__ALLGN - )&~(__ALLGN - ));//最后三位为0一定是8的倍数
}
//当区块已分配给用户后,free_list_link指针不再使用,不会浪费空间
union obj
{
union obj *free_list_link;
char client_data[];
};
static obj *volatile free_list[__NFREELISTS];//16个链表表头指针
//确定使用几号free-list
static size_t FREELIST_INDEX(size_t bytes)
{
return (((bytes)+__ALLGN - ) / __ALLGN - );
}
//当free-list没有可用区块时,为free-list重新填充空间,新的空间取自内存池,调用chunk_alloc函数
static void *refill(size_t n);
//从内存池中取空间给freelist
static char *chunk_alloc(size_t size, int &nobjs); static char *start_free;//内存池起始位置
static char *end_free;//内存池结束位置
static size_t heap_size; public:
static void *allocate(size_t n);
static void deallocate(void *p, size_t n);
static void *reallocate(void *p, size_t old_sz, size_t new_sz);
}; template<bool threads, int inst>
char *__default_alloc_template<threads, inst>::start_free = ; template<bool threads, int inst>
char *__default_alloc_template<threads, inst>::end_free = ; template<bool threads, int inst>
char *__default_alloc_template<threads, inst>::heap_size = ; template<bool threads, int inst>
char *__default_alloc_template<threads, inst>::free_list[__NFREELISTS] = { , , , , , , , , , , , , , , , }; //空间配置函数allocate()
template<bool threads, int inst>
void *__default_alloc_template<threads, inst>::allocate(size_t n)
{
obj * volatile *my_free_list;
obj *result; //大于128调用第一级配置器
if (n > __MAX_BYTES)
{
return (malloc_alloc::allocate(n));
}
//寻找合适的free-list
my_free_list = free_list + FREELIST_INDEX(n);
result = *my_free_list;//free list中某链表的头指针
if (result == )
{
//没找到可用的free list,准备重新填充free list
void *r = refill(RAND_MAX(n));
return r;
}
//调整free-list
*my_free_list = result->free_list_link;
return result;
} //空间释放函数deallocate()
template<bool threads, int inst>
void __default_alloc_template<threads, inst>::deallocate(void *p, size_t n)
{
obj *q = (obj *)p;
obj *volatile *my_free_list; if (n > (size_t)__MAX_BYTES)
{
malloc_alloc::deallocate(p, n);
return;
} my_free_list = free_list + FREELIST_INDEX(n);
//*my_free_list为数组元素,链表头指针
q->free_list_link = *my_free_list;
*my_free_list = q;
} //当free list中没有可用区块时,refill()为free list重新填充空间
template<bool threads, int inst>
void *__default_alloc_template<threads, inst>::refill(size_t n)
{
//新的空间取自内存池,缺省取得20个新区块
int nobjs = ;
char *chunk = chunk_alloc(n, nobjs);
obj * volatile *my_free_list;
obj *result;
obj *current_obj, *next_obj;
int i;
//只获得一个区块,这个区块分配给调用者
if ( == nobjs)
return chunk; my_free_list = free_list + FREELIST_INDEX(n); result = (obj *)chunk;//返回给用户
//在chunk空间内建立free list
*my_free_list = next_obj = (obj *)(chunk + n);
for (i = ;; i++)
{
current_obj = next_obj;
next_obj = (obj *)((char *)next_obj + n);
if (nobjs - == i)
{
current_obj->free_list_link = ;
break;
}
else
{
current_obj->free_list_link = next_obj;
}
}
return result;
} 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
{
//内存池剩余空间连一个区块的大小都无法提供
//从堆中配置内存,大小为需求量的两倍再加上一个随着配置次数增加而愈来愈大的附加量
size_t bytes_to_get = * total_bytes + ROUND_UP(heap_size >> );
//尝试利用内存池残余
if (bytes_left > )
{
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 ( == start_free)
{
//heap空间不足
int i;
obj *volatile *my_free_list, *p;
//在free-list中搜寻未用且足够大的区块释放至内存池,然后再分配
for (i = size; i <= __MAX_BYTES; i += __ALLGN)
{
my_free_list = free_list + FREELIST_INDEX(i);
p = *my_free_list;
if ( != p)
{
*my_free_list = p->free_list_link;
start_free = (char *)p;
end_free = start_free + i;
//递归调用chunk_alloc,为了修正nobjs
return (chunk_alloc(size, nobjs));
}
}
//到处都没内存可用
end_free = ;
//调用第一级配置器,要么抛出异常,要么改善内存不足的情况
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));
}
} //SGL为alloc包装一个接口,alloc为第一级或第二级配置器模板类,SGISTL容器都使用simple_alloc接口
template <class T,class Alloc>
class simple_alloc
{
public:
static T* allocate(size_t n)
{
return n == ? : (T*)Alloc::allocate(n*sizeof(T));
}
static T*allocate(void)
{
return (T*)Alloc::allocate(sizeof(T));
}
static void deallocate(T *p, size_t n)
{
if (n != )
Alloc::deallocate(p, n*sizeof(T));
}
static void deallocate(T *p)
{
Alloc::deallocate(p, sizeof(T));
}
}; //SGL容器使用配置器的方式:
//第二个template参数所接受的缺省参数alloc,可以是第一级配置器,也可以是第二级配置器
template<class T,class Alloc=alloc>
class vector
{
public:
typedef T value_type;
//...
protected:
//专属的空间配置器
typedef simple_alloc<value_type, Alloc>data_allocator;
//...
};

stl空间配置器alloc的更多相关文章

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

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

  2. 【转】STL空间配置器

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

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

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

  4. STL空间配置器

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

  5. 咬碎STL空间配置器

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

  6. STL空间配置器那点事

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

  7. STL空间配置器解析和实现

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

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

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

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

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

随机推荐

  1. JavaScript01天学习笔记分享

    01知识点 JavaScript 代码运行在浏览器(后缀名.js) 和java完全不同的东西,只是名称类型而已 src 引用脚本   <Script></Script> ale ...

  2. Sql生成不重复的数字

    -- ============================================= -- Author:TUZI -- Create date: 2016.4.18 -- Descrip ...

  3. android中用Intent传数据,如果用传递的是一个类,就将类实现Parcelable接口

    Parcelable,内存单位,跨进程使用,或者intent传递对象的时候使用.android中用Intent传数据,如果用传递的是一个对象,就将对象实现Parcelable接口,而不是将对象序列化. ...

  4. Struts工作机制

    Struts工作机制? 为什么要使用Struts?工作机制:Struts的工作流程:在web应用启动时就会加载初始化ActionServlet,ActionServlet从struts-config. ...

  5. 【sqli-labs】 对于less34 less36的宽字节注入的一点深入

    1.AddSlashes() 首先来观察一下是如何通过构造吃掉转义字符的 先将less 34的网页编码换成gbk 加上一些输出 echo "Before addslashes(): &quo ...

  6. vs2017 创建C#类时添加文件头

    C#类模板地址:C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\ItemTemplates\C ...

  7. (转)淘淘商城系列——使用solrj来测试索引库

    http://blog.csdn.net/yerenyuan_pku/article/details/72892280 我们使用solrj来操作索引库,一般习惯先建一个单元测试类测试下增删改查方法是否 ...

  8. 校内测之zay与银临 (day2)(只有T1)

    一些与题目无关的碎碎念 推出式子来一定要化简!!!freopen不要写错!!!特判不要瞎搞!!!! 做到以上三点能高35分qwq T1 江城唱晚 你看数据那么大,显然又是一道数学题. 这里有n个种海棠 ...

  9. Android studio 开发一个用户登录界面

    Android studio 开发一个用户登录界面 activity_main.xml <?xml version="1.0" encoding="utf-8&qu ...

  10. 数据结构---二叉搜索树BST实现

    1. 二叉查找树 二叉查找树(Binary Search Tree),也称为二叉搜索树.有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree),是指一 ...