当前位置:网站首页>stl alloc 空间分配器 代码解析
stl alloc 空间分配器 代码解析
2022-04-22 05:36:00 【xkxsxkx】
这里是对https://github.com/zouxiaohang/TinySTL中的alloc的进行解析
下面这个仓库写的真好,文中的很多信息都是来自于该仓库
参考:https://github.com/steveLauwh/SGI-STL
解析stl是一种对艺术的享受
在计算机的发展中,内存一直是最重要的三个部分之一,而内存面临的主要问题,就在于如何进行高效的分配,以及内存碎片化问题,为了在一定程度上解决这些问题,stl中提供了一种方案,这就是空间配置器
空间配置器,分为两级,
- 当配置区块超过 128 bytes,就使用第一级配置器
- 当配置区块小于 128 bytes,使用内存池管理
空间配置器包含,动态空间配置、空间管理、空间释放
那么这两级是如何设计的呢?
void *alloc::allocate(size_t bytes){
// EMaxBytes::MAXBYTES = 128
/* 这里大于128,就直接调用malloc */
if (bytes > EMaxBytes::MAXBYTES){
return malloc(bytes);
}
// 小于128,
/* // 根据区块大小,决定使用第n号free-list, n从0开始计算 该函数用来计算当前的链表节点序号 static size_t FREELIST_INDEX(size_t bytes) { // return ((bytes + 8 - 1)/8 - 1); return ((bytes + EAlign::ALIGN - 1)/EAlign::ALIGN - 1); } 对于碎片化的内存,配置器中使用的是链表来存储可用的空间 可以看下面的图片,可以更好的理解存储过程 */
size_t index = FREELIST_INDEX(bytes);
obj *list = free_list[index];
if (list){
//此list还有空间给我们
free_list[index] = list->next;
return list;
}
else{
//此list没有足够的空间,需要从内存池里面取空间
/* // 将bytes 上调至8的倍数 static size_t ROUND_UP(size_t bytes) { return ((bytes + EAlign::ALIGN - 1) & ~(EAlign::ALIGN - 1)); } */
return refill(ROUND_UP(bytes));
}
}
free-list 是指针数组,16 个数组元素,就是 16 个 free-list,各自管理大小分别为 8, 16, 24, 32,…128 bytes(8 的倍数)的小额区块。
小额区块的结构体 union _Obj 使用链表连接起来

用到的变量声明
static char *start_free;//内存池起始位置
static char *end_free;//内存池结束位置
char *alloc::start_free = 0;
char *alloc::end_free = 0;
size_t alloc::heap_size = 0;
alloc::obj *alloc::free_list[alloc::ENFreeLists::NFREELISTS] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
//free-lists的节点构造
union obj{
union obj *next;
char client[1];
};
static obj *free_list[ENFreeLists::NFREELISTS];
如果在链表中有剩余的空间,那么就直接取用,但如果没有足够的剩余呢?
那就要调用一下下面这个函数
// 返回一个大小为n的对象,并且有时候会为适当的free_list增加节点
// 假设bytes已经上调为8的倍数
void* alloc::refill(size_t bytes) {
// ENObjs::NOBJS = 20;
size_t nobjs = ENObjs::NOBJS;
// 该函数的解析在下面
char *chunk = chunk_alloc(bytes, nobjs);
obj **my_free_list = 0;
obj *result = 0;
obj *current_obj = 0, *next_obj = 0;
if (nobjs == 1) {
// 取出空间只够一个对象使用
return chunk;
} else {
my_free_list = free_list + FREELIST_INDEX(bytes);
result = (obj*)(chunk);
*my_free_list = next_obj = (obj*)(chunk + bytes);
// 将取出多余的空间加入到相应的free-list里面去
for (int i = 1; ; ++i) {
current_obj = next_obj;
next_obj = (obj*)((char*)next_obj + bytes);
if (nobjs - 1 == i) {
current_obj->next = 0;
break;
} else {
current_obj->next = next_obj;
}
}
return result;
}
}
//假设bytes已经上调为8的倍
char *alloc::chunk_alloc(size_t bytes, size_t& nobjs){
char *result = 0;
// 需要的块大小和相应的块数目
size_t total_bytes = bytes * nobjs; // 需要申请的空间大小
// 通过start_free 和 end_free , 初始状态下两者都是0,说明空间为空
size_t bytes_left = end_free - start_free; // 计算内存池剩余空间
if (bytes_left >= total_bytes){
// 内存池剩余空间完全满足需要
result = start_free;
// 开始指针移动,表示该段空间已使用
start_free = start_free + total_bytes;
return result;
} else if (bytes_left >= bytes){
// 内存池剩余空间不能完全满足需要,但足够供应一个或以上的区块
// 计算可以供给的内存块数目,这里的两步是为了计算8的整数块
nobjs = bytes_left / bytes;
total_bytes = nobjs * bytes;
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){
// 将剩余的内存块,插入到合适大小的内存块链表中
obj **my_free_list = free_list + FREELIST_INDEX(bytes_left);
((obj *)start_free)->next = *my_free_list;
*my_free_list = (obj *)start_free;
}
// 配置heap空间,用来补充内存池
start_free = (char *)malloc(bytes_to_get);
if (!start_free){
// heap 空间不足,malloc 失败
obj **my_free_list = 0, *p = 0;
// 0 ~ 128 , 8
for (int i = 0; i <= EMaxBytes::MAXBYTES; i += EAlign::ALIGN){
// 遍历空闲链表
/* 因为之前的分配要的太多了,所以就从更小内存块申请 */
my_free_list = free_list + FREELIST_INDEX(i);
p = *my_free_list;
if (p != 0){
// 空闲链表节点有效
*my_free_list = p->next;
// 单个内存块大小
start_free = (char *)p;
end_free = start_free + i;
return chunk_alloc(bytes, nobjs);
}
}
// 内存空间清零
end_free = 0;
}
// 堆大小
heap_size += bytes_to_get;
// 扩展空间
end_free = start_free + bytes_to_get;
return chunk_alloc(bytes, nobjs);
}
}
释放内存
void alloc::deallocate(void *ptr, size_t bytes){
// > 128, 释放由malloc分配的内存
if (bytes > EMaxBytes::MAXBYTES){
// 释放申请的大块内存
free(ptr);
}
else{
// 碎片内存,重新归入内存池
size_t index = FREELIST_INDEX(bytes);
obj *node = static_cast<obj *>(ptr);
node->next = free_list[index];
free_list[index] = node;
}
}
// 重新分配,释放旧大小,申请新的大小
void *alloc::reallocate(void *ptr, size_t old_sz, size_t new_sz){
deallocate(ptr, old_sz);
ptr = allocate(new_sz);
return ptr;
}
版权声明
本文为[xkxsxkx]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_38836770/article/details/119548734
边栏推荐
猜你喜欢

数位dp(模板)

MySQL 第6章 Navicat 的安装与使用

01背包问题(模板)

再见2020,2021我来了

Using easyexcel to export excel forms

生成excel模板(下拉选、多级联动)

I/O基础知识入门
![[nanny installation tutorial] download MySQL 5 from the source code of Linux operating system seven](/img/1a/f2b3da4aa6df9deccf2d1376744b7a.png)
[nanny installation tutorial] download MySQL 5 from the source code of Linux operating system seven

DolphinDB VSCode 插件使用教程

2022 Niuke winter vacation supplementary question record 2
随机推荐
线程间定制化通信(ReentrantLock)
MySQL表约束和表设计
MySQL JDBC programming
2022 Niuke winter vacation supplementary question record 2
2.words平均长度
枚舉和Lambda錶達式
POI 和 EasyExcel练习
strlen的三种实现方法你知道吗?
Write a program to automatically generate the two-color ball number of welfare lottery with MATLAB
New tips for JS in 2022
MySQL存储时间的最佳实践
MySQL 第7章 对数据表的复杂查询
Pratique du langage C (2) - - mise en oeuvre de l'addition polynomiale par liste liée
Five important properties of binary tree
The signal isolator is used in the water treatment control system to solve the problem of limitation due to some on-site non electric installation conditions
mysql中on duplicate key update 使用详解
7-10 最长对称子串 (25 分)(暴力题解)C语言
6.Reversal
Auto. JS canvas setting anti aliasing paint setAntiAlias(true);
雷达设备(贪心)