文章目录
-
- 1. loki::allocator 结构
- 2. loki::allocator 使用实例
- 3. loki::allocator 具体实现
-
- 3.1 Chunk 部分实现
- 3.2 FixedAllocator 部分实现
- 4. loki::allocator 总结
loki::allocator 是由C++编委会一成员所写,可找到的最新版本是 loki-0.1.7.exe,所以从未发行过。但是并不妨碍学习其中的设计思路和实现方法。其实现颇有暴力美学的味道,但是又能够较好的实现功能,相比于std::alloc,其能够对所管理的内存进行 delete[] 操作(即进行内存回收,交给os,详细见下),同时由于版本迭代很少,也有一定数量的 bug 也会在下面的内容中予以指出。
源码地址见:https://github.com/zhanglipingGitHub/BeautifulCode
同时推荐看下:【C++内存管理】loki::allocator 源码分析
1. loki::allocator 结构
loki::allocator 可分为三个嵌套结构,自下而上分别为 Chunk,FixedAllocator,SmallObjAllocator。
2. loki::allocator 使用实例
上图中chunk改为block。下图表示的是以p5,p6,p4,p7的顺序对指针所指位置进行 Deallocate() 之后的结果,具体为
myAlloc.Deallocate(p#,64);
,所得到的结果图即是下图。
3. loki::allocator 具体实现
3.1 Chunk 部分实现
loki::allocator中的Chunk的实现细节如下,分为Fixed::allocator::Chunk::Init(),Reset() 和 Release()。其中 Release() 确实是实现了对回收内存的释放。
Chunk::Allocate()实现如下,即是由firstAvailableBlock的序号和pData的位置来计算要分配的内存地址的位置,同时减少block存量(–blocksAvailableBlock_)。
Chunk::Deallocate()的实现如下。指针强转之后,将firstAvailableBlock_更改为p的序号,增加block的存量(++blocksAvailableBlock_)。
3.2 FixedAllocator 部分实现
Allocate()逻辑为:若是当前Chunk仍有block可供分配,则直接分配;若是没有则遍历所有的Chunks,若是找到有可分配内存的Chunk则进行分配,若是没有找到则重新申请一块内存空间,并将其初始化为Chunk,再进行分配。
Deallocate() 则是先调用VicinityFind ( p ) 函数找到需要 deallocate 的位置再调用 DoDeallocate(p)进行内存释放操作。
VicinityFind()函数主要用于查找 指向所要进行回收的内存 的 指针 所对应的 Chunk是哪个。从FixedAllocator所指的deallocChunk(即上次释放中所指定的chunk)向上和向下进行暴搜,直至找到p所处的chunk为止,再将上次请求释放的空间给释放掉,更新deallocChunk信息。同时有个bug就是,如果p不属于FixedAllocator所管理的内存空间,则会导致死循环。
FixedAllocator::DoDeallocate()是FixedAllocator进行内存回收的函数。其中调用了Chunk的 Deallocate() 进行内存空间回收 和 Release() 进行内存空间归还给os 的操作。具体的归还细节不表,但是可看出是使用了 Defering 技法的。此外,该版本下的 bug 也在图片中已经写明。
4. loki::allocator 总结
- 曾有两个 bug,见 FixedAllocator 部分实现章节,其中的 VinicityFind() 和 DoDeallocate() 的函数实现;
- 精简强悍,但是手段暴力(
的使用);for(;;)
- 使用array代替list,即数组(vector)代替链表,同时使用索引(index)下标代替指针(pointer);
- 能够以简单的方式(
)判定是否进行 chunk 全回收,进而将 memory 归还给操作系统;deallocChunk_->blocksavAilable_ == numBlocks
- 有Deferring(暂缓归还)的能力;
- 和 std::alloc 一样,是一种 allocator,用来分配大量小块不带 cookie 的 memory blocks,由 SBH/malloc 分配的内存带有 cookie,它的最佳客户是容器,但是其本身却 has-a vector。
相比于之前分析的 std::alloc 的内存管理:
- std::alloc 一旦向 OS 索取了新的 chunk,就不会还给 OS 了,一直在自己的掌控之中。因为它里面的指针拉扯比较复杂,几乎不可能去判断一块 chunk 中给出去的 block 是否全部归还了。但是 loki::allocator 通过利用一个 blocksAvailable_ 变量,就很容易的判断出某一块 chunk 中的 block 是否已经全部归还了,这样就可以归还给 OS。
- std::alloc 只负责一些特定 block size 的内存管理。如果客户端需要的 block size 它并不支持,那个客户端的 block size 会被取整到最接近的大小 (当然前提是小于它所能够分配的最大的 block size);但是 loki::allocator 能够为不大于最大 block size 的所有 block size 服务。