Как эффективно отслеживать указатели в настраиваемом распределителе кучи для дефрагментации? - PullRequest
0 голосов
/ 19 ноября 2018

Я пытаюсь создать игровой движок, потому что он мне очень интересен, поэтому я получил несколько книг, одна из которых: Архитектура игрового движка, второе издание Джейсон Грегори, Я попытался уйти от того, о чем говорилось в книге, чтобы создать собственный распределитель кучи, но в книге только что упоминалось, как это сделать, поэтому я в итоге сделал распределитель кучи более медленным, чем new / delete. Очевидно, что пользовательские распределители с предварительно выделенной памятью должны быть быстрее, потому что это позволяет избежать переключения контекста в ОС, но у меня это намного медленнее. Я думаю, это из-за того, как я отслеживаю выделенные указатели для дефрагментации. Поэтому мне было интересно , как лучше всего отслеживать «распределенные» указатели и как я могу оптимизировать свой код или я неправильно понял книгу, и она не быстрее. Кроме того, я знаю, что это может быть огромным мероприятием, однако я нахожу это очень интересным и готов учиться, поэтому, если вы можете указать мне на некоторые учебники, которые будут оценены по достоинству.

.h Файл:

    typedef std::uint32_t U32;
typedef std::uint8_t U8;

class HeapAllocator
{
private:
    struct HeapMarker {
        HeapMarker(void* start, size_t size_bytes) {
            this->start = start;
            this->size_bytes = size_bytes;
            this->pointerToStartPointer = &start;
        }

        void* start;
        void** pointerToStartPointer;
        size_t size_bytes;
    };

    void* m_buffer;
    size_t m_maxSize;
    size_t m_bufferSize = 0;
    std::vector<HeapMarker> m_markers;

public:
    void init(U32 heapSize_bytes, U32 guessAtBlockNum);
    void shutDown();

    void* allocUnaligned(U32 size_bytes);
    void* allocInEmptySpace(U32 size_bytes);
    void* allocAligned(size_t size_bytes, size_t alignment);

    void freeUnaligned(void* pRawMem);
    void freeAligned(void* pMem);

    void clear();

    void defrag();
};

.cpp Файл:

void HeapAllocator::init(U32 heapSize_bytes, U32 guessAtBlockNum) {
    this->m_buffer = malloc(heapSize_bytes);
    this->m_maxSize = heapSize_bytes;

    this->m_markers.reserve(guessAtBlockNum);
}

void HeapAllocator::shutDown() {
    this->clear();

    free(m_buffer);
    m_buffer = nullptr;
}

void* HeapAllocator::allocUnaligned(U32 size_bytes) {

    if (m_maxSize - m_bufferSize < size_bytes) {
        void* output = allocInEmptySpace(size_bytes);
        assert(output != nullptr);

        return output;
    }

    /* ******** NO EMPTY BLOCKS WERE FOUND SO CREATE A NEW ONE *********** */

    // Move buffer pointer to the front of the heap and allocate a new block of memory
    if(m_markers.size() > 0)
        m_buffer = m_markers[m_markers.size() - 1].start;

    m_buffer = static_cast<char*>(m_buffer) + size_bytes;
    m_bufferSize += size_bytes;

    // Create a new block of memory in the list for the one that was just created
    void* outputBlock = m_buffer;
    m_markers.emplace_back(HeapMarker(outputBlock, size_bytes));
    m_markers.back().pointerToStartPointer = &outputBlock;

    return outputBlock;
}

void* HeapAllocator::allocInEmptySpace(U32 size_bytes) {
    // Attempt to find an empty location within the heap to avoid defrag
    for (U32 i = 0; i < m_markers.size(); i++) {
        if (m_markers[i].start == nullptr && m_markers[i].size_bytes > size_bytes) {
            // Move buffer pointer to the start of the empty block and allocate the new block of memory
            m_buffer = m_markers[i].start;
            m_buffer = static_cast<char*>(m_buffer) + size_bytes;
            void* outputBlock = m_buffer;

            // Create a new block in the list for the empty space created
            m_markers.emplace_back(HeapMarker(outputBlock, m_markers[i].size_bytes - size_bytes));

            // Turn the old block into the new one that's in use
            m_markers[i].start = outputBlock;
            m_markers[i].size_bytes = size_bytes;
            m_markers[i].pointerToStartPointer = &outputBlock;

            return outputBlock; // Return the pointer to the new memory address
        }
    }

    return nullptr;
}

void* HeapAllocator::allocAligned(size_t size_bytes, size_t alignment) {
    return nullptr;
}

void HeapAllocator::freeUnaligned(void* pRawMem) {

}

void HeapAllocator::freeAligned(void* pMem) {

}

void HeapAllocator::clear() {
    m_buffer = m_markers[m_markers.size() - 1].start;
    m_buffer = static_cast<char*>(m_buffer) - m_bufferSize;
}

void HeapAllocator::defrag() {

}
...