我试图实现一个简单的内存管理器,以实验内存池机制并跟踪内存泄漏。我正在使用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
所以我想问题是这个选项如何解决内存访问的问题。
根据 微软关于运行时库选项的文档, /MD
将该程序与 MSVCRT.lib
这反过来又使链接器能够解析外部引用。这显然修复了由调试模式引发的未处理的异常(内存访问违规错误)。
我不知道我是否应该将其标记为问题的答案或附加细节,所以如果你认为有必要,请自由编辑。