Valgrind检测到意外内存泄漏,求C++程序泄漏根源分析
构造函数抛异常时Valgrind检测到的内存泄漏根源解析
问题代码
#include <iostream> #include <cstring> #include <stdexcept> class cmdline { char *stored_file = nullptr; public: cmdline(const int argc, char const* const* argv) : stored_file(argc < 6 ? throw std::logic_error("Not enough parameters") : new char[std::strlen(argv[1]) + 1]) { } ~cmdline() { delete[] stored_file; } }; int main(int argc, char *argv[]) { using namespace std; cmdline *p; try { p = new cmdline(argc, argv); } catch(const logic_error& err) { cout << err.what() << endl; exit(1); } return 0; }
疑问点
在cmdline类的构造函数中,当满足argc < 6条件时会抛出std::logic_error异常,原本认为构造函数不会分配任何内存,但使用valgrind --leak-check=full运行程序后,检测到了内存泄漏。
Valgrind检测输出
==9845== ==9845== HEAP SUMMARY: ==9845== in use at exit: 190 bytes in 2 blocks ==9845== total heap usage: 5 allocs, 3 frees, 73,926 bytes allocated ==9845== ==9845== 46 bytes in 1 blocks are possibly lost in loss record 1 of 2 ==9845== at 0x4841F11: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==9845== by 0x4966049: allocate (new_allocator.h:137) ==9845== by 0x4966049: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) [clone .isra.0] (cow_string.h:3537) ==9845== by 0x4966116: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) [clone .part.0] [clone .isra.0] (cow_string.h:3096) ==9845== by 0x49664F7: std::logic_error::logic_error(char const*) (cow-stdexcept.cc:87) ==9845== by 0x1093B9: cmdline::cmdline(int, char const* const*, int) (test.cpp:11) ==9845== by 0x109267: main (test.cpp:22) ==9845== ==9845== 144 bytes in 1 blocks are possibly lost in loss record 2 of 2 ==9845== at 0x48417AB: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==9845== by 0x493BB44: __cxa_allocate_exception (eh_alloc.cc:284) ==9845== by 0x1093A4: cmdline::cmdline(int, char const* const*, int) (test.cpp:11) ==9845== by 0x109267: main (test.cpp:22) ==9845== ==9845== LEAK SUMMARY: ==9845== definitely lost: 0 bytes in 0 blocks ==9845== indirectly lost: 0 bytes in 0 blocks ==9845== possibly lost: 190 bytes in 2 blocks ==9845== still reachable: 0 bytes in 0 blocks ==9845== of which reachable via heuristic: ==9845== stdstring : 46 bytes in 1 blocks ==9845== suppressed: 0 bytes in 0 blocks ==9845== ==9845== For lists of detected and suppressed errors, rerun with: -s ==9845== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
泄漏根源分析
这两处"possibly lost"的内存并非来自你代码中new char[]的分配,而是异常机制本身的内存开销:
- 46字节的块:是
std::logic_error内部存储错误消息的std::string分配的内存。当创建std::logic_error对象时,构造函数会把传入的C字符串复制到内部的字符串成员中,这部分内存是在堆上分配的。 - 144字节的块:是C++运行时通过
__cxa_allocate_exception为std::logic_error异常对象本身分配的内存,用于在栈展开过程中传递异常。
内存未被释放的直接原因是catch块中调用了exit(1):exit()会直接终止程序,跳过C++异常处理的栈展开收尾步骤——异常对象的销毁逻辑本应在栈展开完成后执行,调用exit()会导致这部分逻辑被跳过,异常对象及其内部的字符串内存都无法被正确释放,因此Valgrind标记为"possibly lost"。
修复方案
将catch块中的exit(1)替换为return 1,这样程序会正常完成栈展开流程,异常对象会被正确销毁,对应的内存也会被释放:
catch(const logic_error& err) { cout << err.what() << endl; return 1; }
内容的提问来源于stack exchange,提问作者francesco
相关产品推荐
相关产品推荐

