【发布时间】:2020-09-10 00:36:03
【问题描述】:
我正在尝试实现一个简单的内存管理器来试验内存池机制并跟踪内存泄漏。我正在使用 VS2019,到目前为止,我的代码仅在发布 x86 模式下运行。将构建配置更改为调试或将目标平台设置为 x64,会导致访问冲突错误。具体来说,在调试模式下,计算可用池大小的以下行会引发异常“引发未处理的异常:读取访问冲突。p 为 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;
}
}
}
Update-1
我发现将运行时库选项设置为/MD 可以正确编译代码。因此,使用 CL 在命令提示符下编译和链接程序:
>cl /MD app.cpp
所以我想问题是这个选项如何解决内存访问问题。
【问题讨论】:
-
您是否在调试器中单步执行了代码?在初始化
my_pool之前调用new的全局替换。电话似乎来自std::array<std::string, POOL_SIZE> m_adrs_str; -
感谢您的关注。我猜想发布模式通过重新排列/优化我的代码以某种方式自动解决了这个问题,因为在发布模式下调试时,
my_pool被正确初始化,因此没有错误。那么有没有办法找出发布构建优化是什么?在重载new之前如何重新排列代码以初始化my_pool有什么想法吗?
标签: c++ visual-studio memory-management memory-leaks pool