代码拉取完成,页面将自动刷新
#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;
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。