Диспетчер памяти - исключение местоположения записи нарушения доступа - PullRequest
0 голосов
/ 01 февраля 2012

Я провел небольшое исследование по разработке Game Engine и наконец начал пытаться написать Memorymanager.Я получил идею из Книги Дизайна игрового движка от Eberly.В конструкторе я выделяю блок памяти и добавляю к нему верхний и нижний колонтитулы, которые имеют атрибут size и используются.Но теперь я получаю доступ к письму.Я уже что-то слышал о том, что указатели являются константными и доступны только для чтения, но я понятия не имею, как я могу это исправить.

Вот файл MemoryManager.h:

// MemoryManager.h - Header file //

#ifndef H_MemoryManager
#define H_MemoryManager

#include "IMemoryManager.h"

class HeaderBlock
{
public:
bool Used;
unsigned int Size;

HeaderBlock* Prev;
HeaderBlock* Next;
};

class FooterBlock
{
public:
bool Used;
unsigned int Size;
};

class MemoryManager : public IMemoryManager
{
private:
int m_MemoryBudget;
char* m_FullMemory;
HeaderBlock* m_FreeBlock;

int m_hsize;        // Size of the header
int m_fsize;        // Size of the footer
int m_hfsize;       // Size of the HeaderandFooter

public:
// Constructor and Destructor
MemoryManager(int Budget);
virtual ~MemoryManager();

// Functions
virtual char* Allocate(unsigned int RequestSize);
virtual char* Deallocate(char* pDeallocate);

HeaderBlock* SearchByPolicy(unsigned int RequestSize);
 };

#endif

Вот реализация Конструктора:

MemoryManager::MemoryManager(int Budget)
{
m_MemoryBudget = Budget;
m_FullMemory = (char*)malloc(m_MemoryBudget);

m_hsize = sizeof(HeaderBlock);
m_fsize = sizeof(FooterBlock);
m_hfsize = m_hsize + m_fsize;

HeaderBlock* header = (HeaderBlock*)m_FullMemory;
header->Used = false;
header->Size = m_MemoryBudget;

FooterBlock* footer = (FooterBlock*)(m_FullMemory + m_MemoryBudget - m_fsize);
footer->Used = false;
footer->Size = m_MemoryBudget;

header->Prev = header;
header->Next = header;

m_FreeBlock = (HeaderBlock*)m_FullMemory;
}

А вот метод выделения, где я получаю ошибку при ошибке

usedHeader->Used = true;
usedFooter->Used = true;
freeHeader->Used = false; 
freeFooter->Used = false; // HERE I GET THE EXCEPTION

char* MemoryManager::Allocate(unsigned int RequestSize)
{

HeaderBlock* header = SearchByPolicy(RequestSize);


if(header == NULL)
{
    return NULL;
}

unsigned int Size = header->Size;
FooterBlock* footer = (FooterBlock*)((header + Size - m_fsize));

// 1.The size to be allocated fits EXACTLY in the Block pointed by header.
if(Size == RequestSize + m_hfsize)
{
    char* allocated = (char*)header + m_hsize;
    header->Used = true;
    footer->Used = true;

    if(header->Next == header)
    {
        // This is the only block on the free list
        m_FreeBlock = 0;
    }
    else
    {
        m_FreeBlock->Prev->Next = m_FreeBlock->Next;
        m_FreeBlock->Next->Prev = m_FreeBlock->Prev;
        m_FreeBlock = m_FreeBlock->Next;
    }
    return allocated;
}

// 2. The block has more storage than is needed for the allocation request.
if(Size >= RequestSize + 2*m_hfsize)
{
    char* allocated = (char*)(header + m_hsize);

    // Split the block in a "Used"-Block and a "Free"-Block
    HeaderBlock* usedHeader = header;
    FooterBlock* usedFooter = (FooterBlock*)(header + m_hsize + RequestSize);
    HeaderBlock* freeHeader = (HeaderBlock*)(usedFooter + m_fsize);
    FooterBlock* freeFooter = footer;

    usedHeader->Used = true;
    usedFooter->Used = true;
    freeHeader->Used = false;
    freeFooter->Used = false;

    unsigned int usedSize = RequestSize + m_hfsize;
    freeHeader->Size = header->Size - usedSize;
    usedHeader->Size = usedSize;

    freeHeader->Prev = header->Prev;
    freeHeader->Next = header->Next;

    m_FreeBlock = freeHeader;

    return allocated;
}

// 3. The block has more storage then the Request, but to less to divide into two     blocks.
char* allocated = (char*)header + m_hsize;
header->Used = true;
footer->Used = true;

//Detach from the free list;
if(header->Next == header)
{
    // This is the only block on the free list
    m_FreeBlock = 0;
}
else
{
    m_FreeBlock->Prev->Next = m_FreeBlock->Next;
    m_FreeBlock->Next->Prev = m_FreeBlock->Prev;
    m_FreeBlock = m_FreeBlock->Next;
}

return allocated;

}

Я уже проверил, возвращает ли функция SearchByPolicy действительный указатель ион возвращает верный указатель, если может найти больший блок памяти, чем запрос.

Надеюсь, вы мне поможете!

1 Ответ

3 голосов
/ 01 февраля 2012

Ваша проблема связана с арифметикой указателей:

FooterBlock* footer = (FooterBlock*)((header + Size - m_fsize));

означает

FooterBlock* footer = (FooterBlock*)((uint_ptr)header + (sizeof(HeaderBlock) * Size) - (sizeof(HeaderBlock) * m_fsize));

Вы, скорее всего, хотели:

uint_ptr ofs = (uint_ptr)header;
FooterBlock* footer = (FooterBlock*)((ofs + Size - m_fsize));

вы можете найти uint_ptr в stdint.h или UINT_PTR в windows.h


Обновление:

По вопросу в комментарии

IMemoryManager* memorymanager = new MemoryManager(1000000); 
Logger* logger = (Logger*)memorymanager->Allocate(sizeof(Logger)); 
logger->WriteToBuffer(log, "HOI");

это не удастся, потому что конструктор для Logger не будет вызван, есть несколько способов исправить это:

  • вызвать метод построения, хотя и не очень хороший
  • использовать размещение новых:

(к сожалению, списки прерывают форматирование кода, поэтому я должен вставить это здесь ...)

IMemoryManager* memorymanager = new MemoryManager(1000000); 
Logger* logger = new (memorymanager->Allocate(sizeof(Logger))) (); 
logger->WriteToBuffer(log, "HOI");
  • перегрузить операторы ::new и ::delete в глобальном масштабе (очень плохо)
  • создать наследуемый объект для перегрузки new и delete:

Для этого требуется, чтобы диспетчер памяти был доступен в этот момент (или передавался как параметр):

class PoolObject
{
    void* operator new (std::size_t n)
    {
        return memorymanager->Allocate(n);
    }

    void operator delete (void* p)
    {
        memorymanager->Free(p);
    }
}

class Logger : PoolObject
{
}

Logger* logger = new Logger();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...