Speicherverwaltung in Pool Allocator



  • Hallo zusammen,

    ist folgender Allocator valides C++? Habt ihr Verbesserungsvorschläge, außer einen fertigen Allocator zu verwenden 😉

    Die Idee ist den Speicher für mehrere Allokierungen als Block zu besorgen und diesen dann in die geforderte Größe runter zubrechen.

    class ChunkList
    {
       typedef std::vector<char*> MemoryVector;
       typedef std::vector<char*> ChunkVector;
    
       MemoryVector mData; // enthält den allokierten Speicher
       ChunkVector mUnusedChunks; // enthält Offsets in Data mit jeweils Size Größe
       unsigned short mSize;
    
       void allocate(std::size_t chunkCount)
       {
          mUnusedChunks.reserve(mUnusedChunks.size() + chunkCount);
    
          char* data = reinterpret_cast<char*>(::operator new(chunkCount * mSize)); // Kann man hier jedes Object drin konstruieren?
          mData.push_back(data);
    
          for (auto i = 0; i < chunkCount; ++i)
          {
             mUnusedChunks.push_back(data + (i * mSize)); // Gibt er hier Padding oder Alignment Probleme?
          }
       }
    
    public:
       ChunkList(unsigned short size) : mSize(size) {};
       ChunkList(const ChunkList& other) = delete;
       ChunkList& operator=(const ChunkList& other) = delete;
       ChunkList(ChunkList&& other) : mData(std::move(other.mData)), mUnusedChunks(std::move(other.mUnusedChunks)), mSize(other.mSize) {}
    
       ~ChunkList()
       {
          for (auto data : mData)
          {
             ::operator delete(data);
          }
       }
    
       void* allocate()
       {
          if (mUnusedChunks.empty())
          {
             allocate(15);
          }
    
          char* next = mUnusedChunks.back();
          mUnusedChunks.pop_back();
          return next;
       }
    
       void deallocate(void* memory)
       {
          mUnusedChunks.push_back(static_cast<char*>(memory));
       }
    };
    
    template<std::size_t size>
    class FixedAllocator
    {
       std::vector<ChunkList> mChunkLists;
    
       FixedAllocator()
       {
          resize(15);
       }
    
       void resize(int newSize)
       {
          int oldSize = mChunkLists.size();
          if (oldSize >= newSize + 1)
          {
             return;
          }
    
          mChunkLists.reserve(newSize + 1);
          for (int i = oldSize; i < newSize + 1; ++i)
          {
             mChunkLists.emplace_back(i * size);
          }
       }
    
    public:
       static FixedAllocator<size>& inst()
       {
          static FixedAllocator<size> inst;
          return inst;
       }
    
       void* allocate(std::size_t n)
       {
          resize(n);
          return mChunkLists[n].allocate();
       }
    
       void deallocate(std::size_t n, void* p)
       {
          mChunkLists[n].deallocate(p);
       }
    };
    
    template<typename T>
    class ObjectAllocator
    {
       //...
    
       pointer allocate(size_type n, typename std::allocator<void>::const_pointer = 0)
       {
          return reinterpret_cast<pointer>(FixedAllocator<sizeof T>::inst().allocate(n));
       }
    
       void deallocate(pointer p, size_type n)
       {
          FixedAllocator<sizeof T>::inst().deallocate(n, p);
       }
    }
    


  • Ich kann dir nicht sagen, ob das was du da machst gut ist, mich würde aber interessieren, wofür du denkst das zu brauchen?
    Mir fällt als Verwendungszweck für einen Pool nur etwas statischer Natur ein, du verwendest aber in deinem Pool einen std::vector?



  • Mr.Long schrieb:

    Ich kann dir nicht sagen, ob das was du da machst gut ist, mich würde aber interessieren, wofür du denkst das zu brauchen?
    Mir fällt als Verwendungszweck für einen Pool nur etwas statischer Natur ein, du verwendest aber in deinem Pool einen std::vector?

    Ich arbeite zurzeit an einem Schach Programm. Bei der Zuggenerierung für die einzelnen Figuren setzte ich einen std::vector mit diesem Allocator ein, um das wiederholte (de)allokieren von Speicherblöcken zu optimieren.
    Da die benötigten Blockgrößen klein und relativ konstant sind erhoffe ich mir durch die Wiederverwendung einen Performancegewinn.

    typedef std::vector<Move, SmallObjectAllocator<Move>> MoveVector;
    
    MoveVector generateKingMoves(const Board& board, ColorType color)
    {
        // ...
    }
    




  • booster schrieb:

    siehe hier:
    http://www.boost.org/doc/libs/1_47_0/libs/pool/doc/
    http://www.codeproject.com/Articles/27487/Why-to-use-memory-pool-and-how-to-implement-it

    Das es in Boost einen Pool gibt ist mir bekannt, aber wie gesagt möchte ich nichts fertiges verwenden.
    Der zweite Link mach genau das, was ich vorhabe (einen großen Speicherblock anfordern und diesen in Speicherbereiche aufteilen). Danke dafür.


Log in to reply