tc_mem_chunk 的使用

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();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值