SGI的内存管理
来源:互联网 发布:鼠标垫什么牌子好 知乎 编辑:程序博客网 时间:2024/06/11 05:26
1. SGI中的内存管理
在SGI中, 其内存分配把这两步独立出了两个函数:allocate 申请内存,construct 调用构造函数,分别在
2.构造和析构的工具
在stl_construct.h中
//第一个版本destory接受一个指针,然后调用析构函数template <class T>inline void destroy(T* pointer) { pointer->~T();}//构造函数template <class T1, class T2>inline void construct(T1* p, const T2& value) { new (p) T1(value);}//第二个版本的destory,接收两个迭代器,并根据元素的值的类型来调用析构函数,为__false_type,调用析构,为__true_type,直接不管。template <class ForwardIterator>inline void__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type) { for ( ; first < last; ++first) destroy(&*first);}template <class ForwardIterator> inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}template <class ForwardIterator, class T>inline void __destroy(ForwardIterator first, ForwardIterator last, T*) { typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor; __destroy_aux(first, last, trivial_destructor());}template <class ForwardIterator>inline void destroy(ForwardIterator first, ForwardIterator last) { __destroy(first, last, value_type(first));}//特化版本的destroy函数。inline void destroy(char*, char*) {}inline void destroy(wchar_t*, wchar_t*) {}
3.空间配置与释放
考虑到小型区块可能造成的内存破碎问题,SGI设计了双层级配置器。第一级配置器直接使用malloc()和free(),第二级配置器对具体问题使用不同的策略。
3.1 第一级配置器
class __malloc_alloc_template {private://以下函数处理内存不足的情况//oom - out of memorystatic void *oom_malloc(size_t);static void *oom_realloc(void *, size_t);public:static void * allocate(size_t n){ void *result = malloc(n); //第一级配置器直接调用malloc if (0 == result) result = oom_malloc(n);//无法满足需求调用oom_malloc(n) return result;}static void deallocate(void *p, size_t /* n */){ free(p);}static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz){ void * result = realloc(p, new_sz); if (0 == result) result = oom_realloc(p, new_sz); return result;}//参数为void f(),返回值也为void f(),用于自己指定oom handlestatic void (* set_malloc_handler(void (*f)()))(){ void (* old)() = __malloc_alloc_oom_handler; __malloc_alloc_oom_handler = f; return(old);}};void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0;//初始值为0template <int inst>void * __malloc_alloc_template<inst>::oom_malloc(size_t n){ void (* my_malloc_handler)();//声明一个函数指针 void *result; for (;;) {//一直尝试释放,申请 my_malloc_handler = __malloc_alloc_oom_handler; if (0 == 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 (0 == my_malloc_handler) { __THROW_BAD_ALLOC; } (*my_malloc_handler)(); result = realloc(p, n); if (result) return(result); }}
3.2 二级配置器
template <bool threads, int inst>class __default_alloc_template {private: // Really we should use static const int x = N // instead of enum { x = N }, but few compilers accept the former. enum {__ALIGN = 8}; //小型区块的上调边界 enum {__MAX_BYTES = 128};//小型区块的上限 enum {__NFREELISTS = __MAX_BYTES/__ALIGN};//free_list个数 static size_t ROUND_UP(size_t bytes) { return (((bytes) + __ALIGN-1) & ~(__ALIGN - 1));//上调的__ALIGN的倍数 }__PRIVATE: //obj是节点。 union obj { union obj * free_list_link; char client_data[1]; /* The client sees this. */ };private: static obj * __VOLATILE free_list[]; //获得节点的序号,0开始 static size_t FREELIST_INDEX(size_t bytes) { return (((bytes) + __ALIGN-1)/__ALIGN - 1); } // Returns an object of size n, and optionally adds to size n free list. static void *refill(size_t n); // Allocates a chunk for nobjs of size "size". nobjs may be reduced // if it is inconvenient to allocate the requested number. static char *chunk_alloc(size_t size, int &nobjs); // Chunk allocation state. static char *start_free; //内存池的起始位置 static char *end_free; //内存池的结束位置 static size_t heap_size; //堆的大小public: /* n must be > 0 */ //yk:内存分配 static void * allocate(size_t n) { //后面介绍 }; /* p may not be 0 */ //yk : free memory static void deallocate(void *p, size_t n) {//后面介绍 } // reallocate memory static void * reallocate(void *p, size_t old_sz, size_t new_sz);} ;typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc;typedef __default_alloc_template<false, 0> single_client_alloc;//成员函数的初始化template <bool threads, int inst>char *__default_alloc_template<threads, inst>::start_free = 0;template <bool threads, int inst>char *__default_alloc_template<threads, inst>::end_free = 0;template <bool threads, int inst>size_t __default_alloc_template<threads, inst>::heap_size = 0;template <bool threads, int inst>__default_alloc_template<threads, inst>::obj * __VOLATILE__default_alloc_template<threads, inst> ::free_list[# ifdef __SUNPRO_CC __NFREELISTS# else __default_alloc_template<threads, inst>::__NFREELISTS# endif] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };// The 16 zeros are necessary to make version 4.1 of the SunPro// compiler happy. Otherwise it appears to allocate too little// space for the array.
我们最关心的有三点:1. 内存池的创建。2.内存的分配。 3. 内存的释放。
1、SGI内存池的结构
内部的结构体为:
union obj { union obj * free_list_link; char client_data[1]; /* The client sees this. */ };
一个free_list指针指向一个128byte的空间,每个空间根据管理的大小(8,16,32……128),有不同个数的节点数目。为了节省指针的空间, 每个节点为一个union.其中的free_list_link指向下一个空的节点,client_data为柔性数组,大小为当前空间中每个区块的大小。
static obj * __VOLATILE free_list[];
为一个free_list数组,有16个free_list,每个free_list也为一个obj,它有一个指针,指向自己管理的空间第一个节点,它的free_list_link指向第一个自己管理的大小的空间。比如说,#11号区域,刚开始的时候,它是管理一个96byte的空间的,它自己的占用的空间存放的是这个96byte的起始地址,它的free_list_link也是指向这个地址,如果这个空间被别人申请了,那么,申请的时候就会让它指向下一个96byte的空间。
2、内存分配
内存分配的源码如下:
static void * allocate(size_t n) { obj * __VOLATILE * my_free_list; obj * __RESTRICT result; if (n > (size_t) __MAX_BYTES) {//大于128byte,直接调用一级配置器 return(malloc_alloc::allocate(n)); } my_free_list = free_list + FREELIST_INDEX(n);//找到合适的序号的地址 result = *my_free_list; if (result == 0) {//没有找到合适的,准备重新填充 void *r = refill(ROUND_UP(n)); return r; } *my_free_list = result -> free_list_link;//重新调整free_list return (result); };
3、空间释放
static void deallocate(void *p, size_t n) { obj *q = (obj *)p; obj * __VOLATILE * my_free_list; if (n > (size_t) __MAX_BYTES) {//大于128byte,调用第一级配置器 malloc_alloc::deallocate(p, n); return; } //否则回收 my_free_list = free_list + FREELIST_INDEX(n); q -> free_list_link = *my_free_list; *my_free_list = q; }
4、重新填充 free_list,
当free_list中没有可用区块了,就refill(),准备为free_list重新填充空间。新的空间将取自内存池,一般取20个新节点,如果空间不足的话,可能取不到。
template <bool threads, int inst>void* __default_alloc_template<threads, inst>::refill(size_t n){ int nobjs = 20;//默认20个区块 char * chunk = chunk_alloc(n, nobjs);//调用chunk_alloc obj * __VOLATILE * my_free_list; obj * result; obj * current_obj, * next_obj; int i; if (1 == nobjs) return(chunk);//只申请到一个区块,也是惨,直接返回这个区块 my_free_list = free_list + FREELIST_INDEX(n);//申请的比较多的话,my_free_list现在指向n大小的free_list /* Build free list in chunk */ //以下在申请的空间创建free_list result = (obj *)chunk;//保存返回值 *my_free_list = next_obj = (obj *)(chunk + n);//这是第一个 for (i = 1; ; i++) {//从第一个开始,第0个给客户端了。 current_obj = next_obj; next_obj = (obj *)((char *)next_obj + n); if (nobjs - 1 == i) {//没有了 current_obj -> free_list_link = 0; break; } else {//如果还有,指向下一个obj current_obj -> free_list_link = next_obj; } } return(result);}
5、内存池
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) {//如果剩余空间不多,但还是至少有一个size的大小 nobjs = bytes_left/size; //就尽量分给他 total_bytes = size * nobjs; result = start_free; start_free += total_bytes; return(result); } else {//实在没有办法,只能去malloc了 size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4); // Try to make use of the left-over piece. if (bytes_left > 0) {//剩余的空间,直接放到free_list中。因为申请的时候是按8的倍数来申请 //这里不会有小区块的问题 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 (0 == start_free) {//oh,没有申请成功 int i; obj * __VOLATILE * my_free_list, *p; // Try to make do with what we have. That can't // hurt. We do not try smaller requests, since that tends // to result in disaster on multi-process machines. //从自己有的资源里面去找 for (i = size; i <= __MAX_BYTES; i += __ALIGN) { my_free_list = free_list + FREELIST_INDEX(i); p = *my_free_list; if (0 != p) {//这是找到了 *my_free_list = p -> free_list_link; start_free = (char *)p; end_free = start_free + i; return(chunk_alloc(size, nobjs));//调整一下 // Any leftover piece will eventually make it to the // right free list. } } end_free = 0; // In case of exception.实在没有空间了,调用一级配置器,看看oom机制 start_free = (char *)malloc_alloc::allocate(bytes_to_get); // This should either throw an // exception or remedy the situation. Thus we assume it // succeeded. } //这是申请成功的,调用自己,修正nobjs heap_size += bytes_to_get; end_free = start_free + bytes_to_get; return(chunk_alloc(size, nobjs)); }}
举个例子:
1.调用chunk_allock(32,20):malloc分配40个32byte区域,第一块个客户端,19块给free_list[3],剩余20块给内存池
2.调用chunk_allock(64,20):free_list[7]为空,那么向内存池请求,内存池只有10个,就把这10个给他,第一个交给客户端,剩余9个给free_list[7]维护
3(自己加的).调用chunk_allock(32, 20):free_list[6]为空,内存池啥也没有,如果malloc失败,在自己free_list[7]找到一块,把free_list[7]的一个拿出来释放到内存池,然后调用自己,这里,内存池现在有64byte,因此可以申请两个32bytes,一个给客户端,一个由free_list[6]维护
4.接下来调用chunk_alloc(96,20):free_list[11]为空,向内存池请求,内存池也没有,只能调用malloc(),40+n个96bytes区块,d第一个给客户端,19个给free_list[11],剩余20+n给内存池
- SGI的内存管理
- STL SGI内存的管理
- SGI STL 的内存管理
- SGI STL 的内存管理
- SGI STL 的内存管理
- SGI STL 的内存管理
- SGI STL 的内存管理
- SGI STL 的内存管理
- SGI STL 内存管理
- SGI STL 内存管理
- SGI STL 内存管理
- SGI STL内存分配管理
- sgi的内存泄露
- SGI STL的内存池
- SGI STL的内存池
- SGI STL的内存分配器
- SGI STL的内存池
- SGI STL的内存池
- Access在winform下无法进行插入,修改,删除的问题
- 比较原始的QQ大家来找茬的原型
- php 给对象私有及受保护的成员变量赋值的几种方法
- java开发编译器:LR 状态机的缺陷与改进
- 二叉排序树
- SGI的内存管理
- 【Python学习笔记】使用list和tuple
- 谈谈Js继承的那些事儿
- memcached windows安装使用
- 微信公众平台开发[2] —— 微信端分享功能
- 【Android笔记】MediaPlayer基本使用方式
- Android Studio使用中遇到V7包问题
- 周志华《机器学习》笔记汇总
- 5-22 龟兔赛跑 (20分)