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

时间:2012-02-01 11:38:32

标签: c++ exception pointers memory-management

我一直在做一些关于游戏引擎开发的研究,最后我开始尝试编写一个Memorymanager。我从Eberly的游戏引擎设计书中得到了这个想法。在构造函数中,我分配一个内存块并为其添加页眉和页脚,它们都具有size属性并使用。但是现在我得到了一个Access Writing Voilation。我已经听说过一些指针是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函数是否返回一个有效指针,如果它能找到比请求更大的内存块,它确实会返回一个有效指针。

我希望你能帮助我!

1 个答案:

答案 0 :(得分:3)

你的问题是指针算法之一:

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_ptrstdint.h中的UINT_PTR找到windows.h


<强>更新

根据评论中的问题

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

这会失败,因为Logger的构造函数不会被调用,有几种方法可以解决这个问题:

  • 调用一种构造方法,虽然不是很好但
  • 使用placement new:

(不幸的是,列出了断码格式,所以我必须在这里插入...)

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