tars源码学习笔记2
释放空间
- 入参为地址时:
- mmca的deallocate中,会先计算要释放的的内存是否在自己的范围内,不在的话递归下去调用下一个mmca的deallocate。如果在自己的范围内的话,会先计算地址在哪一个mca负责的空间内。
- 因为在初始化的时候说过每一个mca管理的分块的数量是一样的,然后是用数量乘块大小来计算出每一个mca的空间,所以在内存空间中,mca是根据块大小由小到大排列的,而且所有大小相同的块是连续在一起的。也是这个原因可以遍历vBlockSize累加计算出pAddr在哪个mca中。
- mca的deallocate直接透传给mc。
- mc中的deallocate会根据记录的blocksize和传入的首地址进行memset清零,然后把当前block设置为第一个可用的block(这里不需要跟原来的对比一下取最小值么?可能要根据使用场景看吧?),可用block数量加一
- 入参为序号(index)时,mmca中也是类似的逻辑,找到相应mca进行调用,在mc中时则是根据序号计算出地址单后走入参为地址的释放空间逻辑。
void TC_MemChunk::deallocate(void *pAddr)
{
assert(pAddr >= _pData);
unsigned char* prelease = static_cast<unsigned char*>(pAddr);
assert((prelease - _pData) % _pHead->_iBlockSize == 0);
memset(pAddr, 0x00, _pHead->_iBlockSize);
*((size_t *)prelease) = _pHead->_firstAvailableBlock;
_pHead->_firstAvailableBlock = static_cast<size_t>((prelease - _pData)/_pHead->_iBlockSize);
assert(_pHead->_firstAvailableBlock == (prelease - _pData)/_pHead->_iBlockSize);
++_pHead->_blockAvailable;
}
void TC_MemChunkAllocator::deallocate(void *pAddr)
{
assert(pAddr >= _pChunk);
_chunk.deallocate(pAddr);
}
void TC_MemMultiChunkAllocator::deallocate(void *pAddr)
{
if(pAddr < (void*)((char*)_pHead + _pHead->_iSize))
{
// pAddr在本mmca的管理地址空间内
char *pChunkBegin = (char*)_pChunk;
for(size_t i = 0; i < _vBlockSize.size(); i++)
{
// 遍历计算大小找到在哪个mca中
pChunkBegin += _allocator[i]->getMemSize();
if((char*)pAddr < pChunkBegin)
{
_allocator[i]->deallocate(pAddr);
return;
}
}
assert(false);
}
else
{
// 不再当前的mmca中,递归查找下一个mmca
if(_nallocator)
{
_nallocator->deallocate(pAddr);
return;
}
}
assert(false);
}
申请空间
- mmca的allocate中会根据入参的指定的申请空间的大小,从大等于所需空间的位置开始遍历mca找空闲block,没有的话从小等于所需空间的位置开始倒序遍历mca找空闲block。如果一个block都没有(说明当前的mmca满了),则递归去下一个mmca找。
- mca也是透传给mc
- mc中会根据_firstAvailableBlock计算出第一个可用的block空间并memset后返回,然后更新_firstAvailableBlock。也可以在参数中一并获取block的index。
- 这里返回的的空间不一定是足量的,所以在上层使用时候会扩容例如后面的hashmap
void* TC_MemChunk::allocate()
{
if(!isBlockAvailable()) return NULL;
unsigned char *result = _pData + (_pHead->_firstAvailableBlock * _pHead->_iBlockSize);
--_pHead->_blockAvailable;
_pHead->_firstAvailableBlock = *((size_t *)result);
memset(result, 0x00, sizeof(_pHead->_iBlockSize));
return result;
}
void* TC_MemChunk::allocate2(size_t &iIndex)
{
iIndex = _pHead->_firstAvailableBlock + 1;
void *pAddr = allocate();
if(pAddr == NULL)
{
iIndex = 0;
return NULL;
}
return pAddr;
}
void* TC_MemChunkAllocator::allocate()
{
return _chunk.allocate();
}
void* TC_MemChunkAllocator::allocate2(size_t &iIndex)
{
return _chunk.allocate2(iIndex);
}
void* TC_MemMultiChunkAllocator::allocate(size_t iNeedSize, size_t &iAllocSize)
{
size_t iIndex;
return allocate2(iNeedSize, iAllocSize, iIndex);
}
void *TC_MemMultiChunkAllocator::allocate2(size_t iNeedSize, size_t &iAllocSize, size_t &iIndex)
{
void *p = NULL;
iIndex = 0;
for(size_t i = 0; i < _allocator.size(); i++)
{
//首先分配大小刚刚超过的
if(_allocator[i]->getBlockSize() >= iNeedSize)
{
size_t n;
p = _allocator[i]->allocate2(n);
if(p != NULL)
{
iAllocSize = _vBlockSize[i];
iIndex += i * getBlockCount() + n;
return p;
}
}
}
//没有比数据更大的数据块了
for(size_t i = _allocator.size(); i != 0 ; i--)
{
//首先分配大小刚刚小于的
if(_allocator[i-1]->getBlockSize() < iNeedSize)
{
size_t n;
p = _allocator[i-1]->allocate2(n);
if(p != NULL)
{
iAllocSize = _vBlockSize[i-1];
iIndex += (i - 1) * getBlockCount() + n;
return p;
}
}
}
//后续的扩展块分配空间, 注意对象是递归的, 因此只需要分配一个块就可以了
if(_nallocator)
{
p = _nallocator->allocate2(iNeedSize, iAllocSize, iIndex);
if(p != NULL)
{
iIndex += _iAllIndex;
return p;
}
}
return NULL;
}
rebuild
- 这个过程看起来像是清空整个mmca,也是很简单的实现了,也是遍历mca到mc中memset,递归rebuild
- 再其他就都是一些获取空间大小啊或者获取第一个最后一个item的小函数了就不细看了
void TC_MemChunk::rebuild()
{
assert(_pHead);
_pHead->_firstAvailableBlock = 0;
_pHead->_blockAvailable = _pHead->_iBlockCount;
memset(_pData, 0x00, _pHead->_iBlockCount*_pHead->_iBlockSize);
unsigned char *pt = _pData;
for(size_t i = 0; i != _pHead->_iBlockCount; pt+= _pHead->_iBlockSize)
{
++i;
memcpy(pt, &i, sizeof(size_t)); //每块第一个直接指向下一个可用的block编号, 变成一个链表
}
}
void TC_MemChunkAllocator::rebuild()
{
_chunk.rebuild();
}
void TC_MemMultiChunkAllocator::rebuild()
{
for(size_t i = 0; i < _allocator.size(); i++)
{
_allocator[i]->rebuild();
}
if(_nallocator)
{
_nallocator->rebuild();
}
}