有关线程资源层的章节讲到过,ThreadCache层只负责256KB以下的内存块的分配与回收。如果用户需要向内存池申请256KB以上的内存块,就需要进行特殊处理了。
一、当申请内存块大于256KB,但是小于等于128页时
此时ThreadCache层的任何一个内存块都无法满足用户需求,但是PageCache层拥有最大128页的Span包,能够满足要求。直接将用户请求的内存块大小按页向上对齐,然后向页缓存资源层申请对应大小的Span包,此包无需切割,直接返回给用户。当用户释放该Span包的时候,也直接交给页缓存资源层处理,插入回对应的页桶即可。
二、当申请内存块大于128页时
此时,内存池内任何一个内存块与Span包都无法满足用户需求了,直接将用户请求的内存块大小按页向上对齐,然后向系统申请如此大小的内存块,将之用Span结构体封装,起始页与Span包的对应关系也要登记进std::unordered_map<PAGE_ID, Span*> Page_Span里(释放时需要查找Span包),之后返回给用户。释放时,将地址转换成页号,根据页号查找到对应的Span包,发现是大于128页的Span包,直接调用系统释放接口释放即可。
适合在封装了线程资源层接口的TLS接口处进行如上改动:
#include "ThreadCache.h"
#include "PageCache.h"
//这里函数的作用是对ThreadCache里的接口做封装,使得每个线程都拥有独有的ThreadCache,并使用本文件的函数从自己的ThreadCache里申请空间
void* ThisThreadAllocate(size_t n)
{
if (pTLSThreadCache == nullptr)
{
pTLSThreadCache = new ThreadCache;
}
if (n > ThreadCache_MaxSize)//如果申请内存大于256KB,则不走线程资源层了,直接向页缓存资源层申请
{
size_t alignedSize = SizeClass::AlignSize(n);
size_t pages = alignedSize >> PAGE_SHIFT;
PageCache::GetPageCache().GetPageCacheMUTEX().lock();
Span* newSpan = PageCache::GetPageCache().NewSpan(pages);
PageCache::GetPageCache().GetPageCacheMUTEX().unlock();
newSpan->is_used = true;
void* ptr =(void*)(newSpan->pageID << PAGE_SHIFT);//直接向中心资源层申请的大号内存,就不需要切割了,直接把整个Span包作为内存块返回
return ptr;
}
return pTLSThreadCache->Allocate(n);
}
void ThisThreadDeAllocate(void* ptr, size_t n)
{
assert(pTLSThreadCache);
if (n > ThreadCache_MaxSize) // 如果回收内存大于256KB, 则不走线程资源层了, 直接回收给页缓存资源层
{
PageCache& pageCache = PageCache::GetPageCache();
pageCache.GetPageCacheMUTEX().lock();
Span* sp = pageCache.BlocksToSpan(ptr);
pageCache.ReleaseSpanToPageCache(sp);
pageCache.GetPageCacheMUTEX().unlock();
return;
}
pTLSThreadCache->DeAllocate(ptr, n);
}
这里的释放接口,仍然有参数size_t n,将在后续进行改进,本身十分简单,建立起分配出去的内存块地址与实际分配的内存块大小的映射即可。