第四章 小型对象分配技术

  • 书上的内容基本上在下面的代码讨论了,但是并没有完全按照书上实现
#include 
#include 
#include 


using std::vector;
using std::map;


/*
管理相同自定义大小的内存块,可以使用的内存总数的限制在于:
1.系统(安装的内存大小)
2.程序类型(32位、64位)
*/
class CFixedAllocator
{
public:
    CFixedAllocator(const size_t nBlockSizeC, 
        const unsigned char nBlockCountC) : nBlockSize_(nBlockSizeC), 
        nBlockCount_(nBlockCountC), pAlloc_(nullptr), pDealloc_(nullptr)
    {
        assert(nBlockCountC);
    }

private:
    //管理相同自定义大小的内存块,内存块总数不超过255个
    struct SChunkMemory
    {
        const bool Init(const size_t nBlockSizeC,
            const unsigned char nBlockCountC);
        void Release();
        void* Allocate(const size_t nBlockSizeC);
        void Deallocate(void* pValue, const size_t nBlockSizeC);

        unsigned char* pData_;                  //分配的内存
        unsigned char nFirstAvailableBlock_;    //第一个可用的区块索引
        unsigned char nBlockAvailableCount_;    //可用区块总数
        /*
        这里的索引与总数都是单字节类型是为了兼容只分配一个字节的情况
        */
    };

private:
    size_t nBlockSize_;
    unsigned char nBlockCount_;
    vector vecChunkMemory_;
    SChunkMemory* pAlloc_;
    SChunkMemory* pDealloc_;
/*
为了提高查找速度,面对每一次分配,并非遍历整个vecChunkMemory_来寻找空间,
而是保存一个指针,指向最近一次分配所使用的SChunkMemory,若其不存在可用空间,
才会引发一次线性查找
*/

public:
    void* Allocate();
    const bool Deallocate(void* pValue);
    const size_t GetBlockSize() const { return nBlockSize_; }
    void Release();
};

const bool CFixedAllocator::SChunkMemory::Init(const size_t nBlockSizeC,
    const unsigned char nBlockCountC)
{
    pData_ = new (std::nothrow) unsigned char[nBlockSizeC * nBlockCountC];
    if (!pData_)
    {
        return false;
    }

    nFirstAvailableBlock_ = 0;
    nBlockAvailableCount_ = nBlockCountC;

    unsigned char* pTem = pData_;
    for (int i = 0; i < nBlockCountC; pTem += nBlockSizeC)
    {
        *pTem = ++i;
        /*
        拿未被使用的区块的第一个字节来放置下一个未被使用的区块的索引,
        这样就有了一个由可用区块组成的单向链表,且无需占用额外内存
        */
    }

    return true;
}

void CFixedAllocator::SChunkMemory::Release()
{
    if (pData_)
    {
        delete[] pData_;
    }
    nBlockAvailableCount_ = 0;
}

void* CFixedAllocator::SChunkMemory::Allocate(const size_t nBlockSizeC)
{
    if (!nBlockAvailableCount_)
    {
        return nullptr;
    }

    unsigned char* pResult = pData_ + nFirstAvailableBlock_ * nBlockSizeC;
    nFirstAvailableBlock_ = *pResult;
    --nBlockAvailableCount_;
    return pResult;
}

void CFixedAllocator::SChunkMemory::Deallocate(void* pValue, 
    const size_t nBlockSizeC)
{
    unsigned char* pRelease = static_cast(pValue);

    assert(pValue >= pData_);
    assert(!((pRelease - pData_) % nBlockSizeC));

    //指明下一个可用内存块Id,道理其实和Init里是一置的
    *pRelease = nFirstAvailableBlock_; 
    nFirstAvailableBlock_ = 
        static_cast((pRelease - pData_) / nBlockSizeC);
    assert(nFirstAvailableBlock_ == (pRelease - pData_) / nBlockSizeC);

    ++nBlockAvailableCount_;
}

void* CFixedAllocator::Allocate()
{
    if (!pAlloc_ || !pAlloc_->nBlockAvailableCount_)
    {
        for (auto it = vecChunkMemory_.begin(); ; ++it)
        {
            if (vecChunkMemory_.end() == it)
            {
                vecChunkMemory_.emplace_back(SChunkMemory());
                if (!vecChunkMemory_.back().Init(nBlockSize_,
                    nBlockCount_))
                {
                    return nullptr;
                }

                pAlloc_ = &vecChunkMemory_.back();
                pDealloc_ = &vecChunkMemory_.front();
                break;
            }
            else if (it->nBlockAvailableCount_)
            {
                pAlloc_ = &*it;
                break;
            }
        }
    }

    return pAlloc_->Allocate(nBlockSize_);
}

const bool CFixedAllocator::Deallocate(void* pValue)
{
/*
策略一:可以专门建立一个vector来保存归还的内存块,当客户进行内存归还的时候,
就将此内存添加到vector中,用户再申请的时候就直接从这个vector中取。
以上这个策略在用户随机分配和归还时候效果好,但是在用户批量分配和批量释放时候,
效果很差,因为其需要维护一个额外的vector

策略二:建立一个指针指向上次进行归还的那个SChunkMemory对象,
如果被归还的指针不属于这个对象,则进行线性查找
*/
    if (pValue >= pDealloc_->pData_ && 
        pValue <= pDealloc_->pData_ + nBlockSize_ * nBlockCount_)
    {
        pDealloc_->Deallocate(pValue, nBlockSize_);
        return true;
    }

    for (auto it = vecChunkMemory_.begin(); it != vecChunkMemory_.end(); 
        ++it)
    {
        if (pValue >= it->pData_ && 
            pValue <= it->pData_ + nBlockSize_ * nBlockCount_)
        {
            it->Deallocate(pValue, nBlockSize_);
            return true;
        }
    }

    return false;
}

void CFixedAllocator::Release()
{
    for (auto it = vecChunkMemory_.begin();
        it != vecChunkMemory_.end(); ++it)
    {
        it->Release();
    }
    vecChunkMemory_.clear();
}


//自己编的  其分配的内存大小可以自定义
class CSmallObjAllocator
{
public:
    CSmallObjAllocator(const unsigned char nBlockCountC = 255) : 
      nBlockCountC_(nBlockCountC) {}

public:
    void* Allocate(const size_t nMemorySizeC);
    const bool  Deallocate(void* pValue, const size_t nMemorySizeC);
    void Release();

private:
    map mapFixAllocator_;
    const unsigned nBlockCountC_;
};

void* CSmallObjAllocator::Allocate(const size_t nMemorySizeC)
{
    auto it = mapFixAllocator_.find(nMemorySizeC);

    if (it != mapFixAllocator_.end())
    {
        return it->second.Allocate();
    }

    mapFixAllocator_.emplace(std::make_pair(nMemorySizeC, 
        CFixedAllocator(nMemorySizeC, nBlockCountC_)));
    return mapFixAllocator_.at(nMemorySizeC).Allocate();
}

const bool CSmallObjAllocator::Deallocate(void* pValue, 
    const size_t nMemorySizeC)
{
    auto it = mapFixAllocator_.find(nMemorySizeC);

    if (it == mapFixAllocator_.end())
    {
        return false;
    }

    return it->second.Deallocate(pValue);
}

void CSmallObjAllocator::Release()
{
    for (auto it = mapFixAllocator_.begin();
        it != mapFixAllocator_.end(); ++it)
    {
        it->second.Release();
    }

    mapFixAllocator_.clear();
}


int main()
{
    CSmallObjAllocator SmallObj;
    void* aPValue[] = 
    {
        SmallObj.Allocate(10), 
        SmallObj.Allocate(10),
        SmallObj.Allocate(1),
        SmallObj.Allocate(2), 
        SmallObj.Allocate(5)
    };

    SmallObj.Deallocate(aPValue[0], 10);
    SmallObj.Deallocate(aPValue[1], 10);
    SmallObj.Deallocate(aPValue[2], 1);
    SmallObj.Deallocate(aPValue[3], 2);
    SmallObj.Deallocate(aPValue[4], 5);

    return 0;
}

你可能感兴趣的:(第四章 小型对象分配技术)