【问题标题】:Memory Manager - Access Violation Writing Location Exception内存管理器 - 访问冲突写入位置异常
【发布时间】:2012-02-01 11:38:32
【问题描述】:

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

希望你能帮帮我!

【问题讨论】:

    标签: c++ exception pointers memory-management


    【解决方案1】:

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

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

    【讨论】:

    • 非常感谢它就像一个魅力~!还有一个问题:假设我有一个指向内存管理器和记录器的指针: IMemoryManager* memorymanager = new MemoryManager(1000000);记录器*记录器=(记录器*)内存管理器>分配(大小(记录器));记录器->WriteToBuffer(log, "HOI");那这有什么问题呢?再次非常感谢你,如果你能回答最后一个问题,我不会再问你任何问题:P 你得到我的投票!
    • @ChristianVeenman:您正在分配一个对象而不初始化它(不会调用构造函数)。请参阅我的更新问题。
    • 好的,非常感谢!你真的很会解释!您认为创建一个构造函数并在构造函数中使用placement new 在分配的内存中对其进行初始化是个好主意吗?顺便说一句,我接受了你的回答!
    • @ChristianVeenman:我不确定你的意思,Logger 的构造函数不会在没有放置 new 的情况下被调用,在这种情况下它并不重要,因为你可以在构造函数中做所有事情
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-26
    • 2011-08-24
    相关资源
    最近更新 更多