其他面经
设计模式
C++性能检测用过什么工具
gdb看backtrace和切换线程
以下是一些常用的多线程调试方法:
1. 查看线程
- 显示所有线程:
info threads
这个命令会显示当前所有线程的编号、线程ID(TID)、状态以及当前的执行位置。每个线程都有一个
gdb
编号,可以用来切换到指定线程。
2. 切换线程
- 切换到指定线程:
thread THREAD_NUM
这里的
THREAD_NUM
是info threads
命令输出中线程的编号。切换到指定线程后,可以使用正常的调试命令,比如backtrace
查看调用栈,print
查看变量等。
3. 设置线程断点
- 对特定线程设置断点:
break function_name thread THREAD_NUM
在指定线程上设置断点。这样只有当指定线程执行到该断点时,程序才会暂停。
- 对所有线程设置断点:
正常的断点会影响所有线程,因此可以直接使用
break
命令,而无需特别指定线程。
4. 控制线程
- 暂停/继续特定线程:
continue
: 继续当前线程的执行。thread THREAD_NUM
: 切换到特定线程后,可以继续执行该线程的调试流程。
注意:
continue
命令会让所有线程继续运行,想要单步调试特定线程时可以结合next
和step
命令操作。
5. 锁和竞态调试
- 设置断点和观察变量:
可以在临界区或共享资源访问代码处设置断点,使用
watch
命令观察共享变量的值变化,帮助发现竞争条件或死锁情况。watch var
- 死锁调试:
使用
thread apply all backtrace
查看所有线程的调用栈,确定是否有线程卡在锁等待或死锁状态。
6. 常用命令总结
- 列出所有线程:
info threads
- 切换线程:
thread THREAD_NUM
- 对指定线程设置断点:
break func_name thread THREAD_NUM
- 查看所有线程的调用栈:
thread apply all backtrace
- 查看特定线程的调用栈:
backtrace
- 继续执行所有线程:
continue
检测内存泄漏
Valgrind
是 Linux 下功能非常强大的内存分析工具,常用于检测 C/C++ 程序的内存泄漏、非法访问、内存越界等问题。它的核心工具是 memcheck
,用于检测内存泄漏和内存访问错误。以下是对 Valgrind
的详细介绍以及使用方法。
Valgrind 的功能
Valgrind
提供了一系列的子工具来检测和分析程序的各种问题,包括:
- Memcheck:检测内存泄漏、无效访问、非法读写、未初始化内存使用等。
- Cachegrind:模拟 CPU 的缓存行为,分析缓存命中率。
- Massif:内存使用分析工具,帮助优化程序的内存使用。
- Helgrind:检测多线程程序中的数据竞争和锁定错误。
- DRD:另一个数据竞争检测工具,类似于 Helgrind。
在检测内存泄漏和非法访问时,通常使用 Memcheck
子工具。
基本使用方法
假设你的可执行文件是 your_program
,你可以通过以下命令使用 Valgrind
来检测内存问题:
valgrind --leak-check=full ./your_program
这个命令将启动 Valgrind
的 memcheck
工具,并运行 your_program
。--leak-check=full
参数会提供详细的内存泄漏报告。
常用参数选项
Valgrind
提供了很多选项来控制内存检测的精度和输出的信息量。以下是一些常用选项:
--leak-check=<yes|no|summary|full>
:设置泄漏检查的详细程度。yes
:显示简单的内存泄漏摘要。summary
:显示泄漏摘要。full
:显示每个泄漏的详细信息,包括堆栈回溯。
--show-leak-kinds=<kind>
:设置报告的泄漏类型,可以选择all
(所有)、definite
(确定泄漏)、possible
(可能泄漏)、reachable
(可达但未释放)、indirect
(间接泄漏)。--track-origins=yes
:显示未初始化值的来源,适合调试复杂内存问题。--log-file=<filename>
:将Valgrind
输出重定向到文件,方便分析。--num-callers=<n>
:设置堆栈回溯的深度,默认是 12。--tool=<toolname>
:选择Valgrind
子工具(如memcheck
、massif
等),默认使用memcheck
。
Valgrind 的输出解释
当运行程序出现内存错误或泄漏时,Valgrind
会输出详细的报告,包括:
- Invalid read/write:表示程序尝试读取或写入无效内存地址,可能是越界或释放后访问。
- Use of uninitialized value:表示程序使用了未初始化的变量。
- Conditional jump or move depends on uninitialized value(s):指条件语句使用了未初始化的变量。
- Memory leaks:报告程序未释放的内存,给出每个泄漏的堆栈信息。
例如,一个典型的内存泄漏报告如下:
==12345== 8 bytes in 1 blocks are definitely lost in loss record 1 of 2
==12345== at 0x4C2B8F6: malloc (vg_replace_malloc.c:299)
==12345== by 0x4005F4: main (example.c:10)
解释:
12345
:Valgrind
为该进程分配的 ID。8 bytes
:泄漏的内存大小为 8 字节。malloc
:内存分配的函数来源。main (example.c:10)
:泄漏发生的代码位置(文件和行号)。