84 跟踪内存分配的简单方法
内存是很重要的,计算机和内存是紧密相联的,如果你只有一个 CPU 而没有 RAM 没有内存,那么你什么都做不了。现在内存问题不像 20 年前那么严重了,我们的电脑有了 8、16、32G 的内存。
而写一个 C++程序是比较难的,它会用到大量内存,所以了解你的程序什么时候分配内存,特别是堆内存是很有用的。如果你知道程序在哪里分配内存,你就有可能减少它,从而能优化你的程序并使其运行得更快,因为在堆上分配内存并不是最好的做法,尤其是在性能关键的代码中,除此之外,能够看到内存被分配到哪里,还可以帮助你更多地了解程序是如何工作的,即使所有正在运行的代码都是你写的,本节将讨论如何准确地看到每个分配从何而来,以及如何跟踪应用程序内内存的整体使用情况,只需编写代码而不依赖任何其它工具,所展示的东西都可以很容易地插入到你现有的应用程序中。
1. 重载 new 操作符
void* operator new(size_t size)
{
std::cout << "Allocating " << size << " bytes\n";
return malloc(size);
} // breakpoint
struct Object
{
int x, y, z;
};
int main()
{
Object* obj = new Object;
std::unique_ptr<Object> obj2 = std::make_unique<Object>();
}
查看发现直接堆分配实例化和 unique_ptr 都会通过调用 new 在堆上分配对象。
可以看到,这样在 new 函数中插入一个断点来精确追踪内存分配的来源有多有用。
2. 重载 delete 操作符
#include <iostream>
#include <memory>
#include <string>
void* operator new(size_t size)
{
std::cout << "Allocating " << size << " bytes\n";
return malloc(size);
}
void operator delete(void* memory, size_t size)
{
std::cout << "Freeing " << size << " bytes\n";
free(memory);
}
struct Object
{
int x, y, z;
};
int main()
{
{
std::unique_ptr<Object> obj2 = std::make_unique<Object>();
}
std::string string = "Cherno";
}
现在使用这两个函数,我们可以创建内存分配跟踪器,我们可以维护一个allocation metrics ,可以确切地知道有多少内存被使用,有多少内存被分配,有多少内存被释放等,这是非常有用的。
struct AllocationMetrics
{
uint32_t TotalAllocated = 0;
uint32_t TotalFreed = 0;
uint32_t CurrentUsage() { return TotalAllocated - TotalFreed; }
};
static AllocationMetrics s_allocation_metrics;
void* operator new(size_t size)
{
s_allocation_metrics.TotalAllocated += size;
return malloc(size);
}
void operator delete(void* memory, size_t size)
{
s_allocation_metrics.TotalFreed += size;
free(memory);
}
struct Object
{
int x, y, z;
};
static void PrintMemoryUsage()
{
std::cout << "Memory Usage: " << s_allocation_metrics.CurrentUsage() << " bytes\n";
}
int main()
{
PrintMemoryUsage();
std::string string = "Cherno";
PrintMemoryUsage();
{
std::unique_ptr<Object> obj2 = std::make_unique<Object>();
PrintMemoryUsage();
}
PrintMemoryUsage();
}
当然你也可以使用 VS 内置的内存分配跟踪分析工具,还有 Valgrind 等一些很好的现成的工具,但本节只是一个快速简单的方法,可以看到你的代码中发生了什么并跟踪它