问题
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
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.
回答1:
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.
来源:https://stackoverflow.com/questions/61967403/custom-memory-manager-works-fine-in-release-mode-but-not-in-debug-mode