central cache
申请内存
也是一个哈希桶结构,映射规则与thread cache 类似,桶锁减小竞争。
central cache 哈希映射的spnlist, spanlist中挂着span,从span中取出对象给thread cache,这个过程是加锁的(桶锁)
spanlist中所有span都没有内存之后需要向 page cache 申请一个新的span对象给thread cache。 span用一个结构体来实现,span中的 use_count 记录分配了多少对象出去 use_count++。
释放内存
当thread_cache过长或者线程销毁,则会将内存释放回central cache中的,释放回来时– use_count。当use_count减到0时则表示所有对象都回到了span,则将span释放回page cache, page cache中会对前后相邻的空闲页进行合并。
span 和 spanlist的设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| struct Span { PAGE_ID _pageId = 0; size_t _n = 0;
Span* _next = nullptr; Span* _prev = nullptr;
size_t _use_Count = 0; void* _freeList = nullptr;
};
class SpanList { public: SpanList() { _head = new Span; _head->_next = _head; _head->_prev = _head; }
void Insert(Span* pos, Span* newSpan) { assert(pos); assert(newSpan);
Span* prev = pos->_prev; prev->_next = newSpan; newSpan->_prev = prev; newSpan->_next = pos; pos->_prev = newSpan; } void Erase(Span* pos) { assert(pos); assert(pos != _head); Span* prev = pos->_prev; Span* next = pos->_next; prev->_next = next; next->_prev = prev; }
private: Span* _head; };
|
CentralCache要设计成单例模式,
然后要实现threadcache如何从centralcache 中申请内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| void* ThreadCache::FetchFromCentralCache(size_t index, size_t size) {
size_t batchNum = std::min(_freeLists[index].MaxSize(), SizeClass::NumMoveSize(size)); if (_freeLists[index].MaxSize() == batchNum) { _freeLists[index].MaxSize() += 2; } void* start = nullptr; void* end = nullptr;
size_t actualNum = CentralCache::GetInstance()->FetchRangeObj(start, end, batchNum, size); assert(actualNum >= 1);
if (actualNum == 1) { assert(start == end); return start; } else { _freeLists[index].PushRange(NextObj(start), end); return start; } }
|
实现FetchRangeObj, 如何给threadCache内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t n, size_t byte_size) { size_t index = SizeClass::Index(byte_size); _spanLists[index]._mtx.lock(); Span* span = GetOneSpan(_spanLists[index], byte_size);
assert(span); assert(span->_freeList); start = span->_freeList; end = start; size_t i = 0; size_t actualNum = 1; while(i < n - 1 && NextObj(end) != nullptr) { end = NextObj(end); i++; actualNum++; } span->_freeList = NextObj(end); NextObj(end) = nullptr;
_spanLists[index]._mtx.unlock();
return actualNum;
}
|
从pageCache中申请内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| Span* CentralCache::GetOneSpan(SpanList& list, size_t byte_size) { Span* it = list.Begin(); while (it != list.End()) { if (it->_freeList != nullptr) { return it; } else { it = it->_next; } }
list._mtx.unlock(); PageCache::GetInstance()->_pageMtx.lock(); Span* span = PageCache::GetInstance()->NewSpan(SizeClass::NumMovePage(byte_size)); PageCache::GetInstance()->_pageMtx.unlock();
assert(span); char* start = (char*)(span->_pageId << PAGE_SHIFT); size_t bytes = span->_n << PAGE_SHIFT; char* end = start + bytes;
span->_freeList = start; start += byte_size; void* tail = span->_freeList;
while (start < end) { NextObj(tail) = start; tail = NextObj(tail); start += byte_size; } list._mtx.lock(); list.PushFront(span);
return span; }
|
目前为止实现了 threadcache 和 central cache 的申请功能, 释放内存部分还未实现。
page cache
central cache 像 page cache申请内存
pageCache初步设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class PageCache {
public: static PageCache* GetInstance() { return &_sInst; } Span* NewSpan(size_t k);
private: SpanList _spanLists[NPAGES]; std::mutex _pageMtx; PageCache() {}; PageCache(const PageCache&) = delete;
static PageCache _sInst; };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
|
Span* PageCache::NewSpan(size_t k) { assert(k > 0 && k < NPAGES); if (!_spanLists[k].Empty()) { return _spanLists->PopFront(); } for (size_t i = k + 1; i < NPAGES; i++) { if (!_spanLists[i].Empty()) { Span* nSpan = _spanLists[i].PopFront(); Span* kSpan = new Span; kSpan->_pageId = nSpan->_pageId; kSpan->_n = k;
nSpan->_n -= k; nSpan->_n -= k;
_spanLists[nSpan->_n].PushFront(nSpan); return kSpan; } } Span* bigSpan = new Span; void* ptr = SystemAlloc(NPAGES - 1); bigSpan->_pageId = (PAGE_ID)ptr >> PAGE_SHIFT; bigSpan->_n = NPAGES - 1;
_spanLists[bigSpan->_n].PushFront(bigSpan);
return NewSpan(k); }
|