优势
- 内存碎片问题。(尽量缓解)
- 性能问题。(提高申请内存的效率)
- 多核多线程环境下,锁竞争问题
结构
threadCache
第一层的结构是一个
class ThreadCache
{
public:
void* Allocate(size_t size);
void Deallocate(void* ptr,size_t size);
void* FetchFromCentralCache(size_t index, size_t size);
void ListTooLong(FreeList* list, size_t size);
private:
FreeList _freelist[NLISTS];
};
_declspec (thread) static ThreadCache* tlslist = nullptr;
TLS技术:使每个线程都有一个tlslist
主要功能:
申请内存,有内存时直接从链表中拿取,没有的话从CentralCache中申请
释放内存:当在一个链表的后面挂的内存达到一定数量的时候,就归还给CentralCache
CentralCache
第二层的结构是:
class CentralCache
{
public:
static CentralCache* GetInstance()
{
return &_inst;
}
//从Page Cache获取一个Span
Span* GetOneSpan(SpanList& spanlist, size_t byte_sizes);
//从中心缓存获取一定数量的对象给Thread Cache
size_t FetchRangeObj(void*&start, void*&end, size_t n, size_t byte_sizes);
//将一定数量的对象释放到span跨度
void ReleaseListToSpan(void* start, size_t size);
private:
SpanList _spanlist[NLISTS];
private:
CentralCache()
{}
CentralCache(CentralCache&) = delete;
static CentralCache _inst;
};
实现功能:
获取内存:当threadCache向CentralCache申请内存时,如果对应的链表上有内存的话,根据计算取出给threadCache,倘若没有,找PageCache申请
合并内存:当对应的span全部被释放的时候,就会进行合并算法,合成一块大内存,还给PageCache
PageCache
第三层的结构是:
class PageCache
{
public:
static PageCache* GetInstance()
{
return &_inst;
}
Span* NewSpan(size_t size);
Span* MapObjectToSpan(void* obj);
void ReleaseSpanToPageCache(Span* span);
private:
SpanList _spanlist[NPAGES];
std::map<PageID, Span*> _idspanmap;
private:
PageCache(){}
PageCache(const PageCache&) = delete;
static PageCache _inst;
};
功能:
申请内存:直接在共享区划分一部分内存,申请128页的,挂在对应的链表上
合并内存:合并对应的span,小的往大合并
性能
- 加锁区间小,只有在对应的CentralCache的对应大小的链表上申请内存时,才需要加锁
- 减少了内存碎片,控制在12%左右
- 一次申请批量,提高了效率