运行时特定节点内存泄漏排查:定位未释放的特定状态对象
定位状态切换中未释放的特定对象问题
需要找出应用状态切换过程中,仅由MakeState(0)创建且在MakeState(1)执行后未被删除的对象。尝试过Visual Studio内存堆分析工具,但无法精准筛选这类对象,实用性不足。
代码示例
#include <vector> #include <map> class MyClass { public: int myNum; }; std::vector<MyClass *> firstStateClasses; std::map<int, MyClass *> stateClasses; void MakeFirstState() { for (int i = 0; i < 10; ++i) { MyClass* firstClass = new MyClass(); firstStateClasses.push_back(firstClass); } } void DeleteFirstState() { for (auto p : firstStateClasses) { delete p; } firstStateClasses.clear(); } void MakeState(int state) { MyClass* randomClass = new MyClass(); stateClasses.insert(std::make_pair(state, randomClass)); } void DeleteState(int state) { auto itr = stateClasses.find(state); if (itr != stateClasses.end()) { delete itr->second; stateClasses.erase(itr); } } int main() { MakeFirstState(); MakeState(0); //Leak is here, state wasnt deleted. MakeState(1); //I need to know here objects that were made only in MakeState(0) and not deleted. DeleteState(1); MakeState(2); DeleteState(2); DeleteFirstState(); }
解决方案
手动追踪(轻量精准)
1. 添加对象生命周期日志
给MyClass增加构造和析构函数,记录创建时的状态ID,运行时直接通过控制台输出定位未释放对象:
#include <iostream> // 新增头文件 class MyClass { public: int myNum; int createState; // 记录对象所属的创建状态 MyClass(int state) : createState(state) { std::cout << "创建状态" << state << "的MyClass,地址:" << this << std::endl; } ~MyClass() { std::cout << "销毁状态" << createState << "的MyClass,地址:" << this << std::endl; } }; // 修改MakeState函数,传入state到构造函数 void MakeState(int state) { MyClass* randomClass = new MyClass(state); stateClasses.insert(std::make_pair(state, randomClass)); }
运行程序后,对比创建和销毁日志,没有对应销毁记录的就是泄漏对象,一眼就能找到state 0的实例。
2. 直接检查存活对象
在需要排查的位置(比如MakeState(1)执行后),遍历stateClasses输出所有存活对象:
// 在main函数的指定检查点添加代码 //I need to know here objects that were made only in MakeState(0) and not deleted. std::cout << "\n===== 当前未释放的状态对象 =====" << std::endl; for (const auto& item : stateClasses) { std::cout << "状态ID:" << item.first << ",对象地址:" << item.second << std::endl; }
这段代码会直接列出所有未被删除的对象,精准定位state 0的泄漏实例。
适配VS堆分析工具的方案
如果想用VS工具精准筛选,给MakeState创建的内存块打自定义标记:
#define STATE_ALLOC_MARKER 0x12345678 // 内存分配钩子函数,给指定内存打标记 int __cdecl AllocHook(int allocType, void* userData, size_t size, int blockType, long requestNumber, const unsigned char* filename, int lineNumber) { if (blockType == _CLIENT_BLOCK && userData != nullptr && *(int*)userData == STATE_ALLOC_MARKER) { // 设置自定义dump回调,方便筛选 _CrtSetDumpClient([](void* data, size_t size) { std::cout << "这是MakeState创建的对象,大小:" << size << std::endl; }); } return TRUE; } void MakeState(int state) { int marker = STATE_ALLOC_MARKER; _CrtSetAllocHook(AllocHook); // 注册钩子 MyClass* randomClass = new MyClass(state); _CrtSetAllocHook(nullptr); // 注销钩子 stateClasses.insert(std::make_pair(state, randomClass)); }
之后用VS堆分析时,过滤带有自定义标记的内存块,再结合前后快照对比,就能精准找出MakeState(0)创建但未释放的对象。
内容的提问来源于stack exchange,提问作者Alkyone
相关产品推荐
相关产品推荐

