当Page Cache接收了一个来自Central Cache的Span,根据Span的起始页的_pageId来对前一页所对应的Span进行查找,并判断该Span,是否处于使用状态,从而看是否可以合并,如果可以合并继续向前寻找。
当该Span前的空闲Span查找完毕后,就根据当前Span的_pageId+Span中的页数_n来向后查找后一页的Span是否为空闲状态,如果为空闲状态就继续向后合并。
这样就可以将切小的内存合并成大的Span,再次申请内存时,可以再从大Span中切分出小的,这样一来就大大减少了内存碎片,提高了空间的利用效率。
// 释放空闲span回到Pagecache,并合并相邻的span
void PageCache::ReleaseSpanToPageCache(Span* span)
{
//将Central不用的Span进行回收
//同时查找该Span的前后页是否属于空闲状态
while (1)
{
PAGE_ID prevId = span->_pageId - 1;
auto ret = _idSpanMap.find(prevId);
if (ret == _idSpanMap.end())//没有找到说明没有该页号,直接break
{
break;
}
Span* prevspan = ret->second;
if (prevspan->_isUse == true)//如果前面的页处于使用状态,直接break
{
break;
}
if (span->_n + prevspan->_n > 128)
{
break;
}
span->_pageId = prevspan->_pageId;
span->_n += prevspan->_n;
_spanList[prevspan->_n].Erase(prevspan);
delete prevspan;
}
while (1)
{
PAGE_ID nextId = span->_pageId + span->_n;
auto ret = _idSpanMap.find(nextId);
if (ret == _idSpanMap.end())//没有找到说明没有该页号,直接break
{
break;
}
Span* nextspan = ret->second;
if (nextspan->_isUse == true)//如果前面的页处于使用状态,直接break
{
break;
}
if (span->_n + nextspan->_n > 128)
{
break;
}
span->_n += nextspan->_n;
_spanList[nextspan->_n].Erase(nextspan);
delete nextspan;
}
if (span->_n == 128)
{
int x = 0;
}
_spanList[span->_n].PushFront(span);
span->_isUse = false;
_idSpanMap[span->_pageId] = span;
_idSpanMap[span->_pageId + span->_n - 1] = span;
}
至此一个完整的申请回收逻辑就完成了,博主也对整个代码进行了测试和改动,可以完成正常内存申请释放的功能以及对内存碎片的回收利用。后面博主还会对代码进行进一步的优化和改进,从而对其中一些不足之处进行补充。