内存管理器-访问冲突写入位置异常

Memory Manager - Access Violation Writing Location Exception

本文关键字:位置 异常 访问冲突 管理器 内存      更新时间:2023-10-16

我一直在做一些关于游戏引擎开发的研究,最终我开始尝试编写一个Memorymanager。我从Eberly的游戏引擎设计书中得到了这个想法。在构造函数中,我分配了一个内存块,并添加了一个页眉和页脚,它们都有size属性并已使用。但现在我得到了一个Access写作空缺。我已经听说指针是const并且只能读取,但我不知道如何解决这个问题。

这是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函数是否返回了一个有效的指针,如果它能找到比请求更大的内存块,它确实会返回一个有效指针。

我希望你能帮助我!

您的问题是指针算术:

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));

您可以在stdint.h中找到uint_ptr,或者在windows.h 中找到UINT_PTR


更新:

根据评论中的问题

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运算符(非常糟糕)
  • 创建一个可继承对象来重载newdelete

这要求内存管理器在该点可用(或作为参数传递):

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();