编译时是否有在gcc中不启用内存管理的选项?
答案 0 :(得分:11)
在调试使用GCC编译的C代码时使用Valgrind的要点:
使用-O0编译代码。在一些相对罕见的情况下(例如内联汇编),您可能需要-O1。 从不使用更高的优化级别。编译器会破坏你的代码,使你的生活变得不可能。变量可以完全消失,函数可以在内联时神秘地消失,循环展开,等等。基本上除了-O0以外的任何其他东西,你都会冒可执行代码与源代码几乎没有相似之处的风险。
使用-g GCC选项将调试符号添加到代码中,并且不要删除可执行文件。与任何其他调试器非常相似,valgrind将使用可用的调试符号生成无限更有用的输出。它们将帮助valgrind匹配内存地址到代码中的特定文件和行号,这是非常宝贵的。
要跟踪内存泄漏和许多其他问题,我建议您运行程序:
valgrind --log-file=valgrind.log --leak-check=full --track-origins=yes --show-reachable=yes ./program
然后查看valgrind.log文件中发现的任何问题。
编辑:
关于我建议的valgrind选项:
- log-file =告诉valgrind将其输出发送到一个文件,我相信当您调试带有输出到控制台的程序时,或者发现很多问题时,可以使事情变得更容易。< / p>
- leak-check = full告诉valgrind告诉你每个泄漏的内存块的详细信息。
- track-originins = yes告诉valgrind找出未初始化值的来源。它与内存泄漏没有任何关系,尽管它可以帮助解决其他问题。但是,它会使您的程序变慢,因此您可能希望删除此选项,并仅在跟踪未初始化的值时添加该选项。
- show-reachable = yes告诉valgrind输出已分配但未释放的内存块,即使在程序退出时仍有指向它们的指针。这些块在技术上丢失/泄漏,因为您仍然有指向它们的指针。但是,它们可以a)指示程序中的逻辑问题(例如,无限增长的列表)b)如果main()在另一个更大的程序中作为函数集成,它们可能并且将成为内存泄漏。最好不要再留下这样的问题了。
有一个--track-fds = yes选项可以帮助找到泄漏的文件描述符而不仅仅是内存。
一些程序员主张在程序结束时释放内存或关闭文件描述符,因为操作系统无论如何都会这样做。虽然 在那里具有性能和代码大小优势,但恕我直言这应该只由经验丰富的程序员完成,而且应该通过删除生产版本的代码来完成,而不是从不写它。否则,这会鼓励不应该允许的错误编码实践。
编辑2:
一个重要的提示:如果valgrind指示代码中存在问题,那么即使您的程序没有崩溃,也很可能是正确的。根据结构对齐,内存分配器行为,平台,编译器版本和标志或月亮的相位,一些“次要”错误(例如,读取超过缓冲区末尾的一个字节)可能保持不可见。如果更改编译器,libc,平台或位数(例如,从64位到32位),那么带有此类问题的代码可能会中断。
答案 1 :(得分:1)
在没有优化的情况下编译程序,使用调试符号编译以获得最佳结果(-O0 -g
)。
现在运行一个程序实例,利用尽可能多的功能,如下所示包装调用:
valgrind ./myprog my prog args
我经常发现将以下标志传递给valgrind很有用:
valgrind --leak-check=full --track-fds=yes --track-origins=yes --malloc-fill=0x80 --free-fill=0x7f ./myprog my prog args
然而,valgrind将提供很多提示,以帮助您了解要通过的参数,如果它找到不太彻底的传递的东西。