c++内存分配器

#pragma once
/*
说明,此源文件内容由LJ类库轴抽取而来,
如有问题请QQ联系作者,QQ:511266323(W意波)(这是原作者的QQ)
加好友时请注明“BlockMemory"或者”LJ类库“字样
*/
#ifdef WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
namespace LJ
{

    //同步操作相关,单次互斥对象
    class MutexOnce
    {
#ifdef WIN32
        long mlock;
#else
        pthread_mutex_t mutex;
#endif
        MutexOnce(const MutexOnce&) {}
        MutexOnce& operator=(const MutexOnce&) { return *(MutexOnce*)0; }
    public:
        MutexOnce();
        ~MutexOnce();
        void Lock();
        bool Try();
        void UnLock();
        void Reset();
    };
#ifdef WIN32
    inline MutexOnce::MutexOnce() :mlock(0) {}
    inline void MutexOnce::Lock() {
        for (;;) {
#ifdef InterlockedCompareExchangePointer
            if (!InterlockedCompareExchange(&mlock, 1, 0))
                return;
#else
            if (!InterlockedCompareExchange((void**)&mlock, (void*)1, (void*)0))
                return;
#endif
            Sleep(0);
        }
    }
    inline bool MutexOnce::Try()
    {
#ifdef InterlockedCompareExchangePointer
        return !InterlockedCompareExchange(&mlock, 1, 0);
#else
        return !InterlockedCompareExchange((void**)&mlock, (void*)1, (void*)0);
#endif
    }
    inline void MutexOnce::UnLock()
    {
        InterlockedExchange(&mlock, 0);
    }
    inline MutexOnce::~MutexOnce() {}
    inline void MutexOnce::Reset() { mlock = 0; }
#else
    inline MutexOnce::MutexOnce() { pthread_mutex_init(&this->mutex, NULL); }
    inline MutexOnce::~MutexOnce() { pthread_mutex_destroy(&this->mutex); }
    inline void MutexOnce::Lock() { pthread_mutex_lock(&this->mutex); }
    inline bool MutexOnce::Try() { return pthread_mutex_trylock(&this->mutex) == 0; }
    inline void MutexOnce::UnLock() { pthread_mutex_unlock(&this->mutex); }
    inline void MutexOnce::Reset() { pthread_mutex_destroy(&this->mutex); pthread_mutex_init(&this->mutex, NULL); }
#endif
    //位操作相关内容
    struct Bits
    {
        //获取i前导0的比特数(32位)
        static int LeftZeroCount32(unsigned long i);
        //获取i前导0的比特数(64位)
        static int LeftZeroCount64(unsigned long long i);
        //获取i前导0的比特数(自动匹配位数)
        static int LeftZeroCount(unsigned long long i) { return LeftZeroCount64(i); }
        //获取i前导0的比特数(自动匹配位数)
        static int LeftZeroCount(unsigned long i) { return LeftZeroCount32(i); }
        //获取i前导0的比特数(自动匹配位数)
        static int LeftZeroCount(unsigned int i) { return LeftZeroCount32(i); }
    };
    inline int Bits::LeftZeroCount32(unsigned long z)
    {
        if (z > 0x0000ffff)
        {
            if (z > 0x00ffffff)
            {
                if (z > 0x0fffffff)
                {
                    if (z > 0x3fffffff)
                    {
                        if (z > 0x7fffffff)return 0; return 1;
                    }   if (z > 0x1fffffff)return 2; return 3;
                }   if (z > 0x03ffffff)
                {
                    if (z > 0x07ffffff)return 4; return 5;
                }   if (z > 0x01ffffff)return 6; return 7;
            }   if (z > 0x000fffff)
            {
                if (z > 0x003fffff)
                {
                    if (z > 0x007fffff)return 8; return 9;
                }   if (z > 0x001fffff)return 10; return 11;
            }   if (z > 0x0003ffff)
            {
                if (z > 0x0007ffff)return 12; return 13;
            }   if (z > 0x0001ffff)return 14; return 15;
        }   if (z > 0x000000ff)
        {
            if (z > 0x00000fff)
            {
                if (z > 0x00003fff)
                {
                    if (z > 0x00007fff)return 16; return 17;
                }   if (z > 0x00001fff)return 18; return 19;
            }   if (z > 0x000003ff)
            {
                if (z > 0x000007ff)return 20; return 21;
            }   if (z > 0x000001ff)return 22; return 23;
        }   if (z > 0x0000000f)
        {
            if (z > 0x0000003f)
            {
                if (z > 0x0000007f)return 24; return 25;
            }   if (z > 0x0000001f)return 26; return 27;
        }   if (z > 0x00000003)
        {
            if (z > 0x00000007)return 28; return 29;
        }   if (z > 0x00000001)return 30; return z != 0 ? 31 : 32;
    }
    inline int Bits::LeftZeroCount64(unsigned long long i)
    {
        if (i < 0x0000000100000000)//很有意思的感觉,呵呵
        {
            if (i < 0x0000000000010000)
            {
                if (i < 0x0000000000000100)
                {
                    if (i < 0x0000000000000010)
                    {
                        if (i < 0x0000000000000004)
                        {
                            if (i < 0x0000000000000002)return 64 - (int)i; return 62;
                        }   if (i < 0x0000000000000008)return 61; return 60;
                    }   if (i < 0x0000000000000040)
                    {
                        if (i < 0x0000000000000020)return 59; return 58;
                    }   if (i < 0x0000000000000080)return 57; return 56;
                }   if (i < 0x0000000000001000)
                {
                    if (i < 0x0000000000000400)
                    {
                        if (i < 0x0000000000000200)return 55; return 54;
                    }   if (i < 0x0000000000000800)return 53; return 52;
                }   if (i < 0x0000000000004000)
                {
                    if (i < 0x0000000000002000)return 51; return 50;
                }   if (i < 0x0000000000008000)return 49; return 48;
            }   if (i < 0x0000000001000000)
            {
                if (i < 0x0000000000100000)
                {
                    if (i < 0x0000000000040000)
                    {
                        if (i < 0x0000000000020000)return 47; return 46;
                    }   if (i < 0x0000000000080000)return 45; return 44;
                }   if (i < 0x0000000000400000)
                {
                    if (i < 0x0000000000200000)return 43; return 42;
                }   if (i < 0x0000000000800000)return 41; return 40;
            }   if (i < 0x0000000010000000)
            {
                if (i < 0x0000000004000000)
                {
                    if (i < 0x0000000002000000)return 39; return 38;
                }   if (i < 0x0000000008000000)return 37; return 36;
            }   if (i < 0x0000000040000000)
            {
                if (i < 0x0000000020000000)return 35; return 34;
            }   if (i < 0x0000000080000000)return 33; return 32;
        }   if (i < 0x0001000000000000)
        {
            if (i < 0x0000010000000000)
            {
                if (i < 0x0000001000000000)
                {
                    if (i < 0x0000000400000000)
                    {
                        if (i < 0x0000000200000000)return 31; return 30;
                    }   if (i < 0x0000000800000000)return 29; return 28;
                }   if (i < 0x0000004000000000)
                {
                    if (i < 0x0000002000000000)return 27; return 26;
                }   if (i < 0x0000008000000000)return 25; return 24;
            }   if (i < 0x0000100000000000)
            {
                if (i < 0x0000040000000000)
                {
                    if (i < 0x0000020000000000)return 23; return 22;
                }   if (i < 0x0000080000000000)return 21; return 20;
            }   if (i < 0x0000400000000000)
            {
                if (i < 0x0000200000000000)return 19; return 18;
            }   if (i < 0x0000800000000000)return 17; return 16;
        }   if (i < 0x0100000000000000)
        {
            if (i < 0x0010000000000000)
            {
                if (i < 0x0004000000000000)
                {
                    if (i < 0x0002000000000000)return 15; return 14;
                }   if (i < 0x0008000000000000)return 13; return 12;
            }   if (i < 0x0040000000000000)
            {
                if (i < 0x0020000000000000)return 11; return 10;
            }   if (i < 0x0080000000000000)return 9; return 8;
        }   if (i < 0x1000000000000000)
        {
            if (i < 0x0400000000000000)
            {
                if (i < 0x0200000000000000)return 7; return 6;
            }   if (i < 0x0800000000000000)return 5; return 4;
        }   if (i < 0x4000000000000000)
        {
            if (i < 0x2000000000000000)return 3; return 2;
        }   if (i < 0x8000000000000000)return 1; return 0;
    }

    //为了加速分配过程,节点将以size_t []动态数组的形式出现,BlockMemoryNode类提供操作size_t []数组节点的方法
    //size_t p[]数组中内容安排:
    //p[0]:已使用元素数
    //p[1]:可用元素对应的位置数组记录索引
    //p[2]:位置记录数组起始索引,数组元素数为iSize
    //p[iSize+2]:内容数组起始索引,内容元素数为bSize
    struct BlockMemoryNode
    {
        //将位置记录数组的index位置设置为相反的状态
        static void set(size_t*p, size_t index)
        {
            p[index / (sizeof(size_t) * 8) + 2] ^= ((size_t)(1ull << (sizeof(size_t) * 8 - 1))) >> (index&(sizeof(size_t) * 8 - 1));
        }
        //获取一个可用的位置的指针并将该位置设置为不可用
        static void*get(size_t*p, size_t iLen, size_t size)
        {
            size_t t = p[1];
            size_t i = t;
            iLen += 2;//iLen转换为终止位置索引
            while (p[i] == 0)//i从2开始
            {
                if (++i == iLen)i = 2;
                if (i == t)return (void*)NULL;
            }
            p[1] = i;
            size_t tmp = (i - 2)*(sizeof(size_t) * 8) + Bits::LeftZeroCount(p[i]);
            set(p, tmp);
            ++p[0];
            return (unsigned char*)(p + iLen) + tmp*size;
        }
        //释放一个内存,成功返回true,size表示分配的块大小
        template<size_t size>static bool free(void* pf, size_t*p, size_t iLen, size_t bLen)
        {
            size_t index = ((unsigned char*)pf - (unsigned char*)(p + 2 + iLen)) / size;
            if (index >= bLen)
                return false;
#ifdef _DEBUG
            if (((p + 2)[index / (sizeof(size_t) * 8)]
                & (((size_t)(1ull << (sizeof(size_t) * 8 - 1))) >> (index&(sizeof(size_t) * 8 - 1)))) != 0)
            {
                throw - 2;//抛出异常
            }
#endif
            size_t tmp = index;
            set(p, tmp);
            --p[0];
            p[1] = tmp / (sizeof(size_t) * 8);
            return true;
        }
        //获取一个内存,失败返回NULL
        inline static void* alloc(size_t*p, size_t iLen, size_t size)
        {
            return get(p, iLen, size);
        }
        //初始化
        static void Initial(size_t*p, size_t iLen, size_t bLen)
        {
            p[0] = p[1] = 0;
            for (size_t i = 2; i < iLen + 2; ++i)p[i] = (size_t)-1;
            size_t mov = (iLen * sizeof(size_t) * 8 - bLen);
            p[iLen + 1] <<= mov;
        }
        static size_t GetIndexLen(size_t bLen)
        {
            return (bLen + sizeof(size_t) * 8 - 1) / (sizeof(size_t) * 8);
        }
        static size_t GetBlockLen(size_t bufferLength, size_t size)
        {
            size_t result = ((bufferLength - 2) * sizeof(size_t) * 8) / (size * 8 + 2);
            while (((result + 1) * sizeof(size_t) * 8 - 1) / (sizeof(size_t) * 8) + (size*result + sizeof(size_t) - 1) / (sizeof(size_t) * 8) > bufferLength - 2)--result;
            return result;
        }
    };
    //块内存对象,用以分配块大小为size字节大小的内存
    template<size_t size>class BlockMemory
    {
        //节点数组,检索以分配内存(升序排列)
        size_t** pArr;
        //数组大小
        size_t arrSize;
        //互斥对象
        MutexOnce mtStatic;
        //节点总数
        size_t NodeCount;
        //已用节点数
        size_t UsedCount;
        //上次有内容节点号
        size_t TmpIndex;
        //索引数组长度
        size_t IndexLength;
        //元素数组长度
        size_t BlockLength;
        //节点大小
        size_t BufferLength;
        //增加新节点
        void AddNode(size_t*);
        //禁止复制和赋值
        BlockMemory(BlockMemory const&) {}
        BlockMemory&operator=(BlockMemory const&) {}
    public:
        //构造函数,参数enableMutex用以指定是否进行多线程同步,参数bufferLength用以指定节点大小(以size_t为单位)
        //注意:块大小在对象生成后需要释放所有内存才能修改
        BlockMemory(bool enableMutex = true, size_t bufferLength = 65536 / sizeof(size_t) - 8);
        //析构函数
        ~BlockMemory() { RemoveAll(); }
        //是否启用多线程同步(默认使用)
        bool EnableMutex;
        //返回一个指针指向一个StructOfSize<size>对象(size字节大小)
        void* Alloc();
        //释放Alloc所分配的内存
        void Free(void*p);
        //移除未使用的节点
        void RemoveEmpty();
        //移除所有节点(如果有内存未释放将抛出异常)
        void RemoveAll();
        //修改块大小,(以size_t为元素的数组元素数)
        void ChangeBufferSize(size_t bufferLength);
        //获取当前块大小
        size_t GetBufferSize() { return BufferLength; }
    };
    template<size_t size>void BlockMemory<size>::AddNode(size_t*p)
    {
        if (pArr == NULL)
        {
            pArr = (size_t**)malloc(4 * sizeof(size_t*));
            arrSize = 4;
            *pArr = p;
            TmpIndex = 0;
        }
        else
        {
            if (NodeCount == arrSize)
            {
                ++arrSize;
                void* pp = realloc(pArr, arrSize * sizeof(size_t*));
                if (pp == 0)throw - 3;//申请内存失败
                pArr = (size_t**)pp;
            }
            if (p > pArr[NodeCount - 1])
            {
                pArr[TmpIndex = NodeCount] = p;
            }
            else if (p < pArr[0])
            {
                for (size_t i = NodeCount; i > 0; --i)
                {
                    pArr[i] = pArr[i - 1];
                }
                pArr[0] = p;
                TmpIndex = 0;
            }
            else
            {
                size_t high = NodeCount - 1;
                size_t low = 1;
                size_t current = NodeCount / 2;
                for (;;)
                {
                    if (pArr[current]>p)
                    {
                        high = current;
                        if (pArr[current - 1] < p)break;
                        size_t tmp = (low + current) / 2;
                        if (current == tmp)
                        {
                            --current;
                        }
                        else current = tmp;
                    }
                    else if (pArr[current] < p)
                    {
                        low = current;
                        size_t tmp = (current + high) / 2;
                        if (current == tmp)
                        {
                            ++current;
                        }
                        else current = tmp;
                    }
                    else break;
                }
                for (size_t i = NodeCount; i>current; --i)
                {
                    pArr[i] = pArr[i - 1];
                }
                pArr[current] = p;
                TmpIndex = current;
            }
        }
        ++NodeCount;
    }
    template<size_t size>BlockMemory<size>::BlockMemory(bool enableMutex, size_t bufferLength)
        :BufferLength(bufferLength), pArr(NULL), UsedCount(0), TmpIndex(0), arrSize(0), NodeCount(0), EnableMutex(enableMutex)
    {
        BlockLength = BlockMemoryNode::GetBlockLen(bufferLength, size);
        IndexLength = BlockMemoryNode::GetIndexLen(BlockLength);
    }
    template<size_t size>void* BlockMemory<size>::Alloc()
    {
        void*p;
        if (EnableMutex)mtStatic.Lock();
        size_t i = NodeCount - 1;
        if (UsedCount == NodeCount)
        {
            size_t* t = (size_t*)malloc(BufferLength * sizeof(size_t));
            BlockMemoryNode::Initial(t, IndexLength, BlockLength);
            p = BlockMemoryNode::alloc(t, IndexLength, size);
            AddNode(t);
        }
        else
        {
            size_t t = TmpIndex;
            if (pArr[t][0] == BlockLength)
            {
                for (;;)
                {
                    if (++t == NodeCount)t = 0;
                    if (pArr[t][0] != BlockLength)break;
                }
                TmpIndex = t;
            }
            p = BlockMemoryNode::alloc(pArr[t], IndexLength, size);
            if (pArr[t][0] == BlockLength)
                UsedCount++;
        }
        if (EnableMutex)mtStatic.UnLock();
        return p;
    }
    template<size_t size>void BlockMemory<size>::Free(void*p)
    {
        if (!p)return;
        if (EnableMutex)mtStatic.Lock();
        if (pArr)
        {
            if (NodeCount == 1 || pArr[1] > p)
            {
                TmpIndex = 0;
                if (BlockMemoryNode::free<size>(p, pArr[0], IndexLength, BlockLength) && pArr[0][0] == BlockLength - 1)UsedCount--;
            }
            else if (pArr[NodeCount - 1] < p)
            {
                TmpIndex = NodeCount - 1;
                if (BlockMemoryNode::free<size>(p, pArr[NodeCount - 1], IndexLength, BlockLength) && pArr[NodeCount - 1][0] == BlockLength - 1)UsedCount--;
            }
            else//二分法查找
            {
                size_t high = NodeCount - 1;
                size_t low = 0;
                size_t current = high / 2;
                for (;;)
                {
                    if (pArr[current]>p)
                    {
                        high = current;
                        size_t tmp = (low + current) / 2;
                        if (current == tmp)
                            --current;
                        else current = tmp;
                    }
                    else if (pArr[current + 1] < p)
                    {
                        low = current;
                        size_t tmp = (current + high) / 2;
                        if (current == tmp)
                        {
                            if (pArr[current + 1]>p)break;
                            ++current;
                        }
                        else current = tmp;
                    }
                    else break;
                }
                if (BlockMemoryNode::free<size>(p, pArr[current], IndexLength, BlockLength) && pArr[current][0] == BlockLength - 1)UsedCount--;
                TmpIndex = current;
            }
        }
        if (EnableMutex)mtStatic.UnLock();
    }
    template<size_t size>void BlockMemory<size>::RemoveEmpty()
    {
        if (EnableMutex)mtStatic.Lock();
        for (size_t t = 0, lt = 0; lt < NodeCount; ++lt)
        {
            pArr[t] = pArr[lt];
            if (pArr[t][0] == 0)
            {
                free(pArr[t]);
                if (TmpIndex == t)TmpIndex = 0;
                else if (TmpIndex>t)--TmpIndex;
                --NodeCount;
            }
            else ++t;
        }
        if (EnableMutex)mtStatic.UnLock();
    }
    template<size_t size>void BlockMemory<size>::RemoveAll()
    {
        if (EnableMutex)mtStatic.Lock();
        if (UsedCount != 0)
        {
            if (EnableMutex)mtStatic.UnLock();
            throw - 1;//有部分内容未释放
        }
        for (size_t t = 0; t < NodeCount; ++t)
        {
            free(pArr[t]);
        }
        free(pArr);
        pArr = NULL;
        NodeCount = 0;
        arrSize = 0;
        if (EnableMutex)mtStatic.UnLock();
    }
    template<size_t size>void BlockMemory<size>::ChangeBufferSize(size_t bufferLength)
    {
        RemoveAll();
        BlockLength = BlockMemoryNode::GetBlockLen(bufferLength, size);
        IndexLength = BlockMemoryNode::GetIndexLen(BlockLength);
    }
}
// myMalloc.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "myMalloc.h"
using namespace LJ;
void* p[10000000];
int main()
{
    //简单测试程序(块大小为123字节)
    BlockMemory<128> mc;
    //申请内存
    for (size_t i = 0; i < 10000000; ++i)
    {
        p[i] = mc.Alloc();
    }
    //释放内存
    for (size_t i = 0; i < 10000000; ++i)
    {
        mc.Free(p[i]);
    }
    //移除所有占用内存
    mc.RemoveAll();
}

猜你喜欢

转载自blog.csdn.net/osummertime/article/details/72150400
今日推荐