[TOC]
| 选项 | 说明 |
|---|---|
| -fsanitize=address | 启用 AddressSanitizer,用于内存访问错误定位 |
-
编写带有内存泄漏的程序:
#include <iostream> int main() { int* data = new int[10]; return 0; }
-
编译
g++ -fsanitize=address -g main.cpp -o mem_leak
-
运行报错
./mem_leak ================================================================= ==2275==ERROR: LeakSanitizer: detected memory leaks Direct leak of 40 byte(s) in 1 object(s) allocated from: #0 0x7fb17b356357 in operator new[](unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:102 #1 0x7fb17bce825e in main /mnt/c/work/example/mem_leak/main.cpp:5 #2 0x7fb17ad59d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 SUMMARY: AddressSanitizer: 40 byte(s) leaked in 1 allocation(s).
| 命令 | 简写 | 说明 |
|---|---|---|
run |
r | 重新开始运行文件 |
start |
- | 单步执行,运行程序,停在第一执行语句 |
quit |
q | 退出GDB |
list |
l | 查看源码(l+n,从第n行开始查看;l+函数名,查看具体函数) |
set |
- | 设置变量的值 |
display |
- | 追踪查看具体变量值(display+变量名,追踪查看一个变量,每次都停下来显示它的值;) |
undisplay |
- | 取消追踪观察变量 |
watch |
- | 设置观察点 |
i watch |
- | 显示观察点 |
break |
b | 设置断点(b+n,在第n行设置断点;b+函数名,在函数开头设置断点;break...if...,设置条件断点) |
delete |
d | 删除断点(d+n,删除第n个断点) |
enable breakpoints |
- | 启用断点 |
disable breakpoints |
- | 禁用断点 |
info breakpoints |
- | 查看当前设置的所有断点 |
next |
n | 单步调试(不进入函数) |
step |
s | 单步调试(进入函数) |
continue |
c | 继续运行 |
finish |
- | 结束当前函数,返回到函数调用点 |
backtrace |
bt | 查看函数的调用栈帧和层级关系 |
frame |
f | 切换函数的栈帧 |
info |
i | 查看函数内部局部变量的数值 |
print |
p | 打印值以及地址 |
x |
- | 查看内存 |
更多的信息使用GDB的help命令查看;
SET(CMAKE_BUILD_TYPE "Debug")
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "$EN{CXXFLAGS} -O3 -Wall")TODO
TODO
使用以下命令来调试正在运行的进程:
gdb pfile PID #pfile为进程文件,PID为进程ID使用以下命令来调试core文件:
gdb core #core:core文件绝对路径Valgrind 的内存检查将被测试程序运行在一个特殊的虚拟机中,该虚拟机会在程序的每一步操作时进行监视和记录,从而在运行时对程序进行动态分析,捕获和跟踪程序执行时的内存操作,并在必要时提供警告或报告。
-
Ubuntu/Debian
sudo apt-get install valgrind
-
CentOS/Fedora
sudo yum install balgrind
-
macos
brew install valgrind
./configure
make
make install-
编写带有内存泄漏的程序:
#include <iostream> int main() { int* data = new int[10]; return 0; }
-
编译
g++ -g main.cpp -o mem_leak
-
使用valgrind检测
valgrind --leak-check=full --show-reachable=yes --show-leak-kinds=all --track-origins=yes ./mem_leak
valgrind的命令格式为:valgrind [工具名(可选)] [工具选项(可选)] [要检测的程序名] [程序选项(可选)]
注意:valgrind 工具的待测程序在编译的时候需要添加"-g"编译参数,以保留程序调试信息。
| 所属工具 | 选项 |
|---|---|
| 通用 | -h --help 帮助--version 查看版本-q --quiet 安静模式-v --verbose 显示详细信息`--trace-children=no |
示例:
TODO细粒度的的内存检查器。
缓冲模拟器,用于标出每一行执行的指令数和导致的缓冲不命中数;
对cachegrind的补充,在cachegrind的基础上增加了调用追踪功能,可以生成函数调用图;
发现条件竞争问题;
堆剖析器,它测量你的程序使用了多少堆内存;
生成可视化的图形需要下载gprof2dot:https://pypi.org/project/gprof2dot/#files
TODO
-
下载源码
# qt环境(搭配qt使用建议使用qBreakpad) git clone git@github.com:buzzySmile/qBreakpad.git cd qBreakpad/third_party git clone git@github.com:google/breakpad.git git clone git@github.com:ithaibo/linux-syscall-support.git lss # vs环境(TODO) # *nix(TODO)
-
编译
# qt环境(直接使用qt creater打开,点击编译) # *nix环境 ./configure make
-
测试(qt+breakpad)
-
新建Qt Console工程,命名为test
-
复制以下内容到test.pro
# qBreakPad需要用到的特性 QT += network CONFIG += thread exceptions rtti stl # 配置qBreakPad头文件和链接库路径 win32:CONFIG(release, debug|release): { LIBS += -L$$PWD/qbreakpadlib/lib/release/ -lqBreakpad DEPENDPATH += $$PWD/qbreakpadlib/lib/release } else:win32:CONFIG(debug, debug|release): { LIBS += -L$$PWD/qbreakpadlib/lib/debug/ -lqBreakpad DEPENDPATH += $$PWD/qbreakpadlib/lib/debug } INCLUDEPATH += $$PWD/qbreakpadlib/include # 设置release模式生成调试信息(MSVC:xx.pdb, *nix/mingw:带调试信息的exe) win32-msvc* { QMAKE_LFLAGS_RELEASE += /MAP QMAKE_CFLAGS_RELEASE += /Zi QMAKE_LFLAGS_RELEASE += /debug /opt:ref } * { QMAKE_CFLAGS_RELEASE += -g QMAKE_CXXFLAGS_RELEASE += -g QMAKE_CFLAGS_RELEASE -= -O2 QMAKE_CXXFLAGS_RELEASE -= -O2 QMAKE_LFLAGS_RELEASE = -mthreads -W } QMAKE_CXXFLAGS_RELEASE += $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO QMAKE_LFLAGS_RELEASE += $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO
-
复制以下信息到指定位置:
# 以下指令需要根据不同平台,文件目录和release/debug模式修改 mkdir -r test/qbreakpadlib/lib cp qBreakpad文件夹/handler/libqBreakpad.a test/qbreakpadlib/lib/release cp qBreakpad文件夹/handler/QBreakpadHandler.h test/qbreakpadlib/include cp qBreakpad文件夹/handler/QBreakpadHandler.cpp test/qbreakpadlib/include cp qBreakpad文件夹/handler/QBreakpadHttpUploader.h test/qbreakpadlib/include cp qBreakpad文件夹/handler/QBreakpadHttpUploader.cpp test/qbreakpadlib/include cp -r qBreakpad文件夹/handler/singletone test/qbreakpadlib/include -
修改main.cpp
#include <QCoreApplication> #include "QBreakpadHandler.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QBreakpadInstance.setDumpPath("./"); int *i = nullptr; *i = 1; return a.exec(); }
-
点击编译运行
注意:debug和release模式要用对应版本的qBreakpad依赖库,不可混用!!!
-
- 对于
mingw环境编译生成的可执行程序,需要先使用工具cv2pdb生产pdb文件(如已有pdb文件,可跳过); - 选择
“File”->“Symbol File Path…”,导入符号文件(*.pdb); - 选择
“File”->“Source File Path…”,导入源代码; - 选择
“File”->“Open Crash Dump…”,导入dump文件; - 输入:!analyze -v 开始进行分析。
注意:有时候会报ntdll.wrong.symbols.dll这类错误,输入以下命令即可:
TODO-
直接将
*.exe,*.dmp,*.pdb(如果有)放到同一目录下,使用vs打开dump文件并调试 -
对于
mingw环境编译生成的可执行程序,需要先使用工具cv2pdb生产pdb文件,并设置源代码路径:依次点击:视图-解决方案管理器-属性-调试源文件;导入源文件所在目录。
-
导出dump文件信息
dump_syms test.exe test.pdb > test.sym head -n1 test.sym > head.txt # 取第一行用于符号信息地址获取 mkdir -p ./symbols/test mv test.sym ./symbols/test minidump_stackwalk ./xx.dmp ./symbols > test.txt
-
使用address2line或其他工具定位错误。
-
在某些环境下无法生成dump文件
你需要检查以下:
- dump文件生成路径。
- 权限不够。
- 是否被其它程序捕获了异常,如:杀毒软件,输入法等。
- Valgrind学习总结
- 实操学会使用内存分析工具Valgrind、LeakSanitizer,帮助检测和定位内存泄漏(C++)
- 一文学会使用 valgrind 工具进行程序内存检查
- Debugging Under Unix:
gdbTutorial - CMake生成可用gdb调试的可执行文件
- Linux下的系统日志管理
- core文件生成及使用gdb调试
- gdb调试coredump(原理篇)
- 性能测试入门——LoadRunner使用初探
- google/breakpad
- buzzySmile/qBreakpad
- Qt-mingw 生成dump文件并使用vs调试定位错误代码
- Qt Windows系统使用QBreakpad实战
- 跨平台的Qt程序崩溃生成Dump文件Breakpad
- Google Breakpad 在 windows下捕获程序崩溃报告
- Google Breakpad 在 windows下捕获程序崩溃报告
- window mingw qbreakpad 生成dump