loki 是书籍 《Modern C++ Design》配套发行的一个 C++ 代码库,里面对模板的使用发挥到了极致,对设计模式进行了代码实现。这里是 loki 库的源码。
ps. 有空是不是应该把里面的设计模式的代码学习学习, hahahah
loki 库里面有两个文件,SmallObj.h 以及 SmallObj.cpp,就是一个内存管理的内,可以单独使用。下面就其源码进行分析。
1. 类层次结构
SmallObj 文件里面有三个类:Chunk
,FixedAllocator
和 SmallObjAllocator
。它们的类层次关系如下,其中SmallObjAllocator
是最上层的,直接供客户端使用的类。
2. Chunk
Chunk
就是直接管理单一内存块的类。它负责向操作系统索取内存块,并将内存块串成 “链表”。
2.1 初始化
先来看看其中的初始化函数 Init()
:
void FixedAllocator::Chunk::Init(std::size_t blockSize, unsigned char blocks)
{
pData_ = new unsigned char[blockSize * blocks];
Reset(blockSize, blocks);
}
void FixedAllocator::Chunk::Reset(std::size_t blockSize, unsigned char blocks)
{
firstAvailableBlock_ = 0;
blocksAvailable_ = blocks;
unsigned char i = 0;
unsigned char* p = pData_;
for (; i != blocks; p += blockSize) //指向下一个可用的 block 的 index
{
*p = ++i;
}
}
- 传入参数为 block 的大小和数量
- 用 operator new 分配出一大块内存 chunk,并用指针
pData_
指向 chunk。 Reset()
函数对这块内存进行分割。利用嵌入式指针的思想,每一块 block 的第一个 byte 存放的是下一个可用的 block 距离起始位置 pData_ 的偏移量(以 block 大小为单位),以这种形式将 block 串成 “链表”。firstAvailableBlock_
表示当前可用的 block 的偏移量;blocksAvailable_
表示当前 chunk 中剩余的 block 数量。
初始状态的 chunk 如下图所示:
2.2 内存分配 allocate
void* FixedAllocator::Chunk::Allocate(std::size_t blockSize)
{
if (!blocksAvailable_) return 0;
unsigned char* pResult =
pData_ + (firstAvailableBlock_ * blockSize);
firstAvailableBlock_ = *pResult;
--blocksAvailable_;
return pResult;
}
这段代码也很好理解,可以结合下图理解:
2.3 内存回收 deallocate
void FixedAllocator::Chunk::Deallocate(void* p, std::size_t blockSize)
{
unsigned char* toRelease = static_cast<unsigned char*>(p);
//链接到链表上
*toRelease = firstAvailableBlock_;
//修改 “头指针”
//回收的 block 指针距离头指针 pData_ 的距离(以 bl