Я пытаюсь создать игровой движок, потому что он мне очень интересен, поэтому я получил несколько книг, одна из которых: Архитектура игрового движка, второе издание Джейсон Грегори, Я попытался уйти от того, о чем говорилось в книге, чтобы создать собственный распределитель кучи, но в книге только что упоминалось, как это сделать, поэтому я в итоге сделал распределитель кучи более медленным, чем 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() {
}