标签:实现 ret 回收 dealloc 填充 对象 img 默认 sts
头文件<memory>
1.1 std::allocate、std::deallocate (通过::operator new 和 ::operator delete封装实现)
1.2 std::construct、std::destory (通过placement new 和调用析构函数实现)
template<class T1, class T2>
inline void h_construct(T1* p, const T2& value)
{
new(p) T1(value);
}
template<class T>
inline void h_destroy(T* pointer)
{
pointer->~T();
}
1.3 std::alloc
STL考虑到小型内存区块问题,存在两个问题:1) 造成内存碎片
2)造成额外负担(索取内存块,需要额外空间用于管理,区块越小,额外负担所占比例越大)
设计了双层级配置器,第一级配置直接使用malloc()和free();第二级配置器则视情况采用不同的策略,当配置区大于128bytes时,直接调用第一级配置器;当配置区块小于128bytes时,便不借助第一级配置器,而使用一个memory pool来实现。究竟是使用第一级配置器还是第二级配置器,由一个宏定义来控制。SGI STL中默认使用第二级配置器。

第二级配置器维护16个free-lists, 各自管理大小为8,16,24...120,128bytes的小额区块。

free-lists节点结构如下,通过union的方式解决了管理节点指针的额外负担,第一个字段构成链表,第二个字段指向实际区块
union obj {
union obj* free_list_link;
char client_data[1]; /* The client sees this. */
};
类构造
class h_alloc
{
private:
enum {
ALIGN = 8, // 对齐边界
MAX_BYTES = 128, // 最大上限
NFREELISTS = MAX_BYTES/ ALIGN // 个数
};
union obj { // 区块对应自由链表的节点结构
union obj* free_list_link;
char client_data[1]; /* The client sees this. */
};
private:
static size_t round_up(size_t bytes) // 对齐函数
{
return (((bytes)+(size_t)ALIGN - 1) & ~((size_t)ALIGN - 1));
}
// 计算使用第n号链表,n从0开始
static size_t freeList_index(size_t bytes)
{
return (((bytes)+(size_t)ALIGN - 1) / (size_t)ALIGN - 1);
}
// 返回一个大小为n的对象,并可能加入大小为n的其他区块到free_list
static void* refill(size_t n);
// 配置个大块空间,可容纳nobjs个size大小的区块
static char* chunk_alloc(size_t size, int& nobjs);
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);
private:
static obj* volatile m_free_list[NFREELISTS];// 16个 free-lists
static char* m_start_free; //内存池起始位置,只在chunk_alloc()中变化
static char* m_end_free; //内存池结束位置,只在chunk_alloc()中变化
static size_t m_heap_size;
};
char* h_alloc::m_start_free = 0;
char* h_alloc::m_end_free = 0;
size_t h_alloc::m_heap_size = 0;
typename h_alloc::obj* volatile h_alloc::m_free_list[NFREELISTS];
1) allocate()函数
void* h_alloc::allocate(size_t n)
{
obj* volatile * my_free_list;
obj* result;
if (n > MAX_BYTES) //大于128字节调用第一级配置器
{
return (malloc(n));
}
else
{
//寻找16个自由链表中合适的一个
my_free_list = m_free_list + freeList_index(n);
result = *my_free_list;
if (result == 0)
{
// 没找到可用的free_list, 重新填充free_list
void *r = refill(round_up(n));
return r;
}
// 调整free_list
*my_free_list = result->free_list_link;
return result;
}
}

2) deallocate()
void h_alloc::deallocate(void* p, size_t n)
{
obj *q = (obj*)p;
obj* volatile * my_free_list;
if (n > MAX_BYTES)
{
free(q);
return;
}
// 寻找对应的free_list
my_free_list = m_free_list + freeList_index(n);
// 调整free_list, 回收区块
q->free_list_link = *my_free_list;
*my_free_list = q;
}
3) refill()
填充自由链表用,缺省一次取20个新节点,具体看内存池大小
void* h_alloc::refill(size_t n)
{
int nobjs = 20; //默认取20个节点
char* chunck = chunk_alloc(n, nobjs);//从内存池申请内存
if (nobjs == 1)
{
return chunck; // 如果只申请到一个节点,不用调整free_list,直接返回
}
obj* volatile * m_free_list = m_free_list + freeList_index(n); //找到n号链表
obj* result = (obj*)chunck; // 保存要返回的结果
obj* next_obj = (obj*)(chunck + n);
*m_free_list = next_obj; //链表第一个节点
// 串联各个节点,第一个节点已经返回出去了
obj* current_objs;
for (int i = 1; ;i++)
{
current_objs = next_obj;
if (nobjs - 1 == i)
{
current_objs->free_list_link = 0;
break;
}
else
{
next_obj = (obj*)(next_obj + n);
current_objs->free_list_link = next_obj;
}
}
return result;
}
4) chunk_alloc()
从内存池取空间给refill函数,内存池不够,从堆空间获取内存给内存池
char* h_alloc::chunk_alloc(size_t size, int& nobjs)
{
size_t total_bytes = size * nobjs;
size_t left_bytes = m_end_free - m_start_free;
char* result;
if(left_bytes > total_bytes) //内存池剩余空间满足需求量
{
result = m_start_free;
m_start_free += total_bytes;
return result;
}
else if (left_bytes > size) //内存池剩余空间不满足需求量,但是足够一个以上的区块
{
nobjs = left_bytes / size;
total_bytes = nobjs * size;
result = m_start_free;
m_start_free += total_bytes;
return result;
}
else //内存池大小不够一个区块
{
size_t bytes_to_get = 2 * total_bytes + round_up(m_heap_size >> 4);
//size_t bytes_to_get = 2 * total_bytes;
if (left_bytes > 0) //残余零头不浪费
{
obj* volatile * m_free_list = m_free_list + freeList_index(left_bytes); //找到n号链表
((obj*)m_start_free)->free_list_link = *m_free_list;
*m_free_list = (obj*)m_start_free;
}
//申请堆空间
m_start_free = (char*)malloc (bytes_to_get);
if (0 == m_start_free)
{
printf("chunk_alloc malloc failed\n");
//申请失败处理,省略。。。
}
m_heap_size += bytes_to_get;
m_end_free = m_start_free + bytes_to_get;
//递归调用,修正nobjs
return (chunk_alloc(size, nobjs));
}
}
标签:实现 ret 回收 dealloc 填充 对象 img 默认 sts
原文地址:https://www.cnblogs.com/ho966/p/11954974.html