自定义内存管理器在发布模式下工作正常,但在调试模式下工作不正常 [英] Custom memory manager works fine in release mode, but not in debug mode

查看:144
本文介绍了自定义内存管理器在发布模式下工作正常,但在调试模式下工作不正常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现一个简单的内存管理器,以试验内存池机制并跟踪内存泄漏.我正在使用VS2019,到目前为止,我的代码仅在发行版x86模式下运行.将构建配置更改为调试或将目标平台设置为x64会导致访问冲突错误.具体来说,在调试模式下,计算可用池大小的以下行将引发异常引发未处理的异常:读取访问冲突.p为nullptr".

I'm trying to implement a simple memory manager to experiment with memory pooling mechanism and track memory leaks. I'm using VS2019 and so far my code only runs in release x86 mode. Changing the build configuration to debug or setting target platform to x64, results in an access violation error. Specifically, in debug mode the following line which calculates the available pool size, throws an exception "Unhandled exception thrown: read access violation. p was nullptr."

    return p->end - p->next;

我的问题是为什么释放模式可以正常工作,以及如何在调试模式配置中解决访问冲突?也赞赏对实施的任何评论,建议或评估.这是我当前的代码:

My question is why release mode works fine and how to fix the access violation in debug mode configuration? Also any comment, suggestions or appraisal of the implementation is appreciated. Here is my current code:

#include <iostream>
#include <string>
#include <array>


struct free_store {
    char* next;
    char* end;
};

const int POOL_SIZE {500};

// memory counters
size_t alloc_count {0};
size_t dealloc_count {0};

// containers to trace memory info
std::array<void*, POOL_SIZE> m_adrs; // addresses of the reserved memory
std::array<size_t, POOL_SIZE> m_sizes; // sizes of the reserved memory
std::array<std::string, POOL_SIZE> m_adrs_str;

// memory management functionality
using pool = free_store;
pool* create_pool(size_t);
void destroy_pool(pool*);
size_t available_pool(pool*);
void* alloc_memory(pool*, size_t);
void free_memory(void* memory);

// test class
class Student {
private:
    const size_t NUM_OF_COURSES {5};
    double* scores;

public:
    Student() {
        scores = new double[NUM_OF_COURSES];
    }
    ~Student() {
        // uncomment to prevent leaks
        // delete[] scores;
    }
};

// customizing new and delete 
pool* my_pool = create_pool(sizeof(Student) * POOL_SIZE);

void* operator new(size_t sz) {
    //void* ptr {malloc(sz)};
    void* ptr = alloc_memory(my_pool, sz);
    return ptr;
}
void operator delete(void* ptr) {
    free_memory(ptr);
    //free(ptr); // I destroy the pool in the end of program
}

void test_1() {
    int* id {new int(208748301)};
    double* pass {new double(15)};
    double* bounds = {new double[2] {0, 20}};
    Student* st1 = new Student;
    Student* st2 = new Student;
    delete pass;
    delete[] bounds;
    delete st1;
    delete st2;
}

void display_results();


int main() {

    // test allocation/deallocation
    test_1();

    // show results
    display_results();

    // release resources
    destroy_pool(my_pool);

    system("pause");

} // end main function



pool* create_pool(size_t size) {
    pool* p = (pool*)malloc(size + sizeof(pool));
    p->next = (char*)&p[1];
    p->end = p->next + size;
    return p;
}

void destroy_pool(pool* p) {
    free(p);
}

size_t available_pool(pool* p) {
    return p->end - p->next;
}

void* alloc_memory(pool* p, size_t sz) {
    std::cout << "Pool Available: " << available_pool(my_pool) << " bytes" << std::endl;
    if(available_pool(p) < sz) return nullptr;
    void* memory = (void*)p->next;
    p->next += sz;
    m_adrs.at(alloc_count) = memory;
    char buf[128];
    sprintf_s(buf, "%p", memory);
    m_adrs_str.at(alloc_count) = buf;
    m_sizes.at(alloc_count) = sz;
    alloc_count++;
    return memory;
}

void free_memory(void* memory) {
    auto it {std::find(m_adrs.begin(), m_adrs.end(), memory)};
    auto idx {std::distance(m_adrs.begin(), it)};
    m_adrs.at(idx) = nullptr;
    dealloc_count++;
}

void display_results() {
    std::cout << std::endl;
    std::cout << "Number of allocations: " << alloc_count << std::endl;
    std::cout << "Number of deallocations: " << dealloc_count << std::endl << std::endl;

    std::cout << "Sizes of the reserved memory:" << std::endl;
    for(size_t i {}; i < m_sizes.size(); i++) {
        if(m_adrs_str[i] != "") {
            std::cout << "Address: " << m_adrs_str[i] << ", Size: " << m_sizes[i] << " bytes" << std::endl;
        }
    }

    std::cout << std::endl;
    std::cout << "Addresses of leaks:" << std::endl;
    for(const auto& a : m_adrs) {
        if(a != nullptr) {
            std::cout << a << std::endl;
        }
    }
}

Update-1

我发现将运行时库"选项设置为/MD可以正确编译代码.因此,要使用CL在命令提示符下编译并链接程序:

I found out setting the Runtime Library option to /MD compiles the code correctly. Therefore to compile and link the program in command prompt using CL:

>cl /MD app.cpp

所以我想问题是此选项如何解决内存访问问题.

So I guess the question is how this option fixes the memory access problem.

推荐答案

根据

According to Microsoft documentation on Run-Time Library options, /MD links the program to MSVCRT.lib which in turn enables the linker to resolve external references. This appreantly fixes unhandled exception (the memory access violation error) thrown by the debug mode.

我不确定是否应该将其标记为答案或问题的其他详细信息,因此,如果您认为有必要,请随时进行编辑.

I'm not sure if I should tag this as an answer or additional details for the question, so feel free to edit if you deem necessary.

这篇关于自定义内存管理器在发布模式下工作正常,但在调试模式下工作不正常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆