加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
ThreadCache.cpp 3.41 KB
一键复制 编辑 原始数据 按行查看 历史
mabay 提交于 2023-03-10 14:27 . 调整
#include "ThreadCache.h"
#include "CentralCache.h"
void ThreadCache::ListTooLong(FreeList& list, size_t size)
{
void* start = nullptr;
void* end = nullptr;
list.PopRange(start, end, list.MaxSize());
CentralCache::GetInstance()->ReleaseListToSpan(start, size);
}
void* ThreadCache::Allocate(size_t size)
{
/*我们大致的思路是:ThreadCache中将一系列同尺寸的内存块按照链表的形式连接起来,共同构成哈希桶的映射结构,并且提供需要尺寸的内存块,如果需要尺寸的内存块用完了,就向Central进行申请。但是如果以1个字节进行划分哈希桶的话,那么256KB就有256*1024的哈希桶,消耗太大。所以我们需要以一定的规则设计哈希桶。
*/
// 我们需要设计对齐和映射规则(控制threadcache尺寸小于256K)
// [1,128] 8byte对齐 freelist[0,16)
// [128+1,1024] 16byte对齐 freelist[16,72)
// [1024+1,8*1024] 128byte对齐 freelist[72,128)
// [8*1024+1,64*1024] ` 1024byte对齐 freelist[128,184)
// [64*1024+1,256*1024] 8*1024byte对齐 freelist[184,208)
assert(size <= MAX_SIZE);
// 获得当前应该申请内存大小
size_t alginSize = SizeClass::RoundUp(size);
// 获得对应哈希桶的下标
size_t index = SizeClass::GetBucketIndex(size);
// 获取内存
void* obj = nullptr;
// 当前哈希桶不为空时
if (!_freeLists[index].Empty())
{
obj = _freeLists[index].Pop();
}
else // 当前哈希桶为空
{
obj = FetchFromCentralCache(index, alginSize);
}
return obj;
}
void ThreadCache::Deallocate(void* ptr, size_t size)
{
assert(ptr);
assert(size <= MAX_SIZE);
// 对应哈希桶的自由链表直接头插即可
size_t index = SizeClass::GetBucketIndex(size);
_freeLists[index].Push(ptr);
// 插入之后进行合并判断
if (_freeLists[index].Size() >= _freeLists[index].MaxSize())
{
ListTooLong(_freeLists[index], size);
}
}
void* ThreadCache::FetchFromCentralCache(size_t index, size_t size)
{
assert(size);
// 慢开始反馈调节算法
// 1、最开始不会一次向central cache一次批量要太多,因为要太多了可能用不完
// 2、如果你不要这个size大小内存需求,那么batchNum就会不断增长,直到上限
// 3、size越大,一次向central cache要的batchNum就越小
// 4、size越小,一次向central cache要的batchNum就越大
// windows.h头文件中也有一个min的宏函数,因为模板的实例化在宏替换的后面,所以优先匹配的宏函数
// size_t batchNum = std::min(_freeList[index].MaxSize(), SizeClass::NumMoveSize(size));
// 直接使用windows.h中的宏函数即可
size_t batchNum = min(_freeLists[index].MaxSize(), SizeClass::NumMoveSize(size));
if (_freeLists[index].MaxSize() == batchNum)
{
_freeLists[index].MaxSize() += 1;
}
// 输出型参数,用来获得用_freeList链接的一批小块内存
void* start = nullptr;
void* end = nullptr;
// 因为当前的span不一定能够满足batchNum的需求,所以这里会返回一个实际的切割数据
size_t actualNum = CentralCache::GetInstance()->FetchRangeObj(start, end, batchNum, size);
// 断言一下,方便debug
assert(actualNum > 0);
// 得到了一批小内存块
if (actualNum == 1)
{
assert(start == end);
}
else
{
// 先将分配的一块内存取出,在将剩下的一小批内存块链表插入_freeLists
_freeLists[index].PushRange(NextObj(start), end, actualNum - 1);
}
return start;
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化