Loki Allocator 有三个类 这玩意对比起 pool allocator 的优点就在于 它有把内存还给系统
但是它作为一个 内存分配器 却在里面使用了 vector 作为容器… 按道理来说 应该在其内部实现一个简易版的 vector 才不会那么奇怪 但也没所谓 只是 先用了一次标准库的分配器 后续使用容器的时候 就可以用 Loki 分配器了.
- Chunk
- FixedAllocator
- SmallObjAllocator
Chunk 解剖
Chunk 是整个分配器的最底层 里面主要是三个 成员变量
1 | // 指向内存块 |
Chunk 的几个关键函数 已进行 剪裁 和 修改
Chunk 分配
分配流程很简单 就是 申请了内存以后 将每个小区块的第一个字节设置为索引 排好号
取的流程:
- 从 当前可用区块的第一块索引中取 得当前可用区块
- 当前可用区块会被返回
- 被返回的可用区块中的索引 被设置到 当前可用区块索引去(这样下一次就会使用到它)
- 可用区块数目 - 1
1 | firstAvailableBlock_ = 4 |
Chunk 回收
存的流程:
- 首先 我们要明确 回收回来的区块 下次分配优先分配
- 计算 回收回来的区块 应该放到哪里 (idx 为索引)
- 那么 当前可用区块的索引号就应该设置为 idx 这样才能保证下次一定先用它
- 那之前的索引号 就会被设置到 回收回来的区块的索引中去(分配完回收的区块后 就会分配之前本应该被分配的区块 后来因为回收了新的区块 而没被分配出去的区块 好绕口…)
- 当前可用区块 + 1
Chunk 函数实现
这块设计我个人觉得有一点不好的地方 就是 Chunk::Init
的时候 会传入 blockSize
但是 Chunk::Allocate
也会传入 blockSize
如果 这两块的 blockSize
不一致 则会出错
个人想法是 在 Init 的时候 将 blockSize
存入 data member 中去 在 Allocator 则不再传入
1 | // 简单的说 就是开辟 blockSize * blocks 那么大内存 |
FixedAllocator 解剖
FixedAllocator 里面存着 vector
1 | // vector<Chunk> |
FixedAllocator 分配
分配流程 简单的说就是 用 Chunk 去分配 那么 FixedAllocator 最主要的任务就是去找 能够分配内存的 Chunk
- 先看看 allocChunk_(指向上次分配过区块的Chunk) 有没有效 有效则直接分配
- 无效 则去找 emptyChunk_(指向一个空Chunk) 有效直接分配
- 无效 则依次遍历 vector 找到 其中一个 能分配区块的 Chunk
- 找不到 则直接 创建一个新的 Chunk 并将其 push_back 到 vector 中
FixedAllocator 回收
回收流程 就是先去找 要回收的区块在哪个 Chunk 中 这里先从 上一次回收过区块的 Chunk 中查看 再从 上一次分配过区块的 Chunk 中查看 如果都没有 则用一种 特殊的搜索方法 就是从 上一次回收过区块的 Chunk 作为临界点 每次循环 一次向上找 一次向下找 直到找到以后 再去调用释放函数 如果发生了全回收 则 看看是否已经有一块全回收了(因为要2块全回收才释放掉其中一块 避免突然又要用到那块Chunk)
FixedAllocator 函数实现
1 | void * FixedAllocator::Allocate( void ) { |
SmallObjAllocator 解剖
1 | // vector<FixedAllocator> 其实是个数组 你可以理解成 vector |
SmallObjAllocator 分配实现
分配内存 简单的说 就是从 vector
1 | void * SmallObjAllocator::Allocate( ::std::size_t numBytes, bool doThrow ) { |
这里有一个有意思的点 SmallObjAllocator::TrimExcessMemory()
这个函数 会遍历所有的 FixedAllocator 然后 调用 FixedAllocator::TrimChunkList()
这里面有一段代码
1 | bool FixedAllocator::TrimChunkList( void ) { |
SmallObjAllocator 回收实现
回收内存 找回收的内存对应的 FixedAllocator 然后调用下一层的 FixedAllocator 去进行真的是回收操作
1 | void SmallObjAllocator::Deallocate( void * p ) { |