自定义内存管理器在发布模式下可以正常工作,但在调试模式下就不行了。

问题描述 投票:0回答:1

我试图实现一个简单的内存管理器,以实验内存池机制并跟踪内存泄漏。我正在使用VS2019,到目前为止,我的代码只能在发布x86模式下运行。将构建配置改为debug或将目标平台设置为x64,结果出现访问违规错误。具体来说,在调试模式下,计算可用池大小的下面一行,抛出一个异常 "Unhandled exception thrown: read access violation.p was nullptr."。

    return p->end - p->next;

我的问题是 为什么释放模式可以正常工作 以及如何在调试模式配置下修复访问违规?同时也感谢大家对实现的任何意见、建议或评价。这是我目前的代码。

#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;
        }
    }
}

Upd-1

我发现将Runtime Library选项设置为 /MD 正确编译代码。因此要在命令提示符下用CL编译和链接程序。

>cl /MD app.cpp

所以我想问题是这个选项如何解决内存访问的问题。

c++ visual-studio memory-management memory-leaks pool
1个回答
0
投票

根据 微软关于运行时库选项的文档, /MD 将该程序与 MSVCRT.lib 这反过来又使链接器能够解析外部引用。这显然修复了由调试模式引发的未处理的异常(内存访问违规错误)。

我不知道我是否应该将其标记为问题的答案或附加细节,所以如果你认为有必要,请自由编辑。

© www.soinside.com 2019 - 2024. All rights reserved.