freeList是一个元素类型为obj*的数组,freeList[i]代表着一串内存区块链表的首地址,每串区块的区块大小是不同的。假设freeList[0]代表一串区块大小为8的区块串,则它有可能是如下的形式
可以看出,在一个区块链表中,每两个obj加上后面没有颜色的一部分即为整个区块的大小。
在这里聪明的你可能会问这样一个问题:为什么要用共用体,只用一个next指针不就完事了吗?
我认为是为了使得存储obj这块空间可以是char*类型的,避免在拿出一块时需要手动
地将obj部分的空间转成char*类型。
----------------------------------------------------------------------------------
至于区块链表是如何初始化的,可以看下面这段代码,链表的创建就在如下代码中的for循环部分。完整代码参考https://github.com/Alinshans/MyTinySTL/blob/master/MyTinySTL/alloc.h,需要注意原代码中有几处bug。
// 分配一个n个字节的区块,n已经被调整为8的整数倍
void* alloc::M_refill(size_t n)
{
size_t nblock = 10;
// 获得nblock个区块
char* c = M_chunk_alloc(n, nblock);
FreeList* my_free_list;
FreeList* result, *cur, *next;
// 如果只有一个区块,就把这个区块返回给调用者,free list 没有增加新节点
if (nblock == 1)
return c;
// 否则把一个区块给调用者,剩下的纳入 free list 作为新节点
my_free_list = free_list[M_freelist_index(n)];
result = (FreeList*)c; // 将第一个区块返回
free_list[M_freelist_index(n)] = my_free_list = next = (FreeList*)(c + n); // 下一个区块的首地址,n >= 2
for (size_t i = 1; ; ++i)
{
cur = next; // 当前区块首地址
next = (FreeList*)((char*)next + n); // 下一个区块的首地址
if (nblock - 1 == i) // 目前的区块是第nblock个了
{
cur->next = nullptr; // 当前区块没有下一个区块了
break;
}
else
{
cur->next = next;
}
}
return result; // 返回一个可用的区块
}
另外,free_list中相邻区块的首地址差的绝对值不一定是一个区块的大小,例如如下的情况:
TinySTL::vector a(8); // a拿到第一个区块
TinySTL::vector b(8); // b拿到第二个区块
a.resize(128); // 重新分配内存,并回收先前分配给a的区块
TinySTL::alloc::showAddress(); // 打印一下free_list
输出结果:
计算一下第一个地址和第二个地址之间的差值
2*16 - 1 * 16 = 16
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)