命令 |
命令缩写 |
命令说明 |
list |
l |
显示多行源代码 |
break |
b |
设置断点,程序运行到断点的位置会停下来 |
info |
i |
描述程序的状态 |
run |
r |
开始运行程序 |
display |
disp |
跟踪查看某个变量,每次停下来都显示它的值 |
step |
s |
执行下一条语句,如果该语句为函数调用,则进入函数执行其中的第一条语句 |
next |
n |
执行下一条语句,如果该语句为函数调用,不会进入函数内部执行(即不会一步步地调试函数内部语句) |
|
p |
打印内部变量值 |
continue |
c |
继续程序的运行,直到遇到下一个断点 |
set var name=v |
|
设置变量的值 |
start |
st |
开始执行程序,在main函数的第一条语句前面停下来 |
file |
|
装入需要调试的程序 |
kill |
k |
终止正在调试的程序 |
watch |
|
监视变量值的变化 |
backtrace |
bt |
产看函数调用信息(堆栈) |
frame |
f |
查看栈帧 |
quit |
q |
退出GDB环境 |
break 函数名
break 行号
break 文件名:函数名
break 文件名:行号
break +偏移量
break -偏移量
break *地址
break可简写成b
info break
可简写成i b
delete <断点id>:删除指定断点
delete:删除所有断点
clear
clear 函数名
clear 行号
clear 文件名:行号
clear 文件名:函数名
break 断点 if 条件;比如break sum if value==9,当输入的value为9的时候才会断住。
condition 断点编号:给指定断点删除触发条件
condition 断点编号 条件:给指定断点添加触发条件
disable
disable 断点编号
disable display 显示编号
disable mem 内存区域
enable
enable 断点编号
enable once 断点编号:该断点只启用一次,程序运行到该断点并暂停后,该断点即被禁用。
enable delete 断点编号
enable display 显示编号
enable mem 内存区域
run运行,如有参数则跟在run命令后,如run 9
如果需要断点在main处,则直接start即可
通过bt可以显示栈帧,bt full可以显示局部变量。
bt
bt full:不仅显示backtrace,还显示局部变量
bt N:显示开头N个栈帧
bt full N
单步执行有两个命令next和step,两者的区别是next遇到函数不会进入函数内部,step会执行到函数内部
如果需要逐条汇编指令执行,可以分别使用nexti和stepi。
调试时,使用continue命令继续执行程序。程序遇到断电后再次暂停执行;如果没有断点,就会一直执行到结束。
continue:继续执行
continue 次数:继续执行一定次数
要想找到变量在何处被改变,可以使用watch命令设置监视点watchpoint。
watch <表达式>:表达式发生变化时暂停运行
awatch <表达式>:表达式被访问、改变是暂停执行
rwatch <表达式>:表达式被访问时暂停执行
要想找到变量在何处被改变,可以使用watch命令设置监视点watchpoint。
watch <表达式>:表达式发生变化时暂停运行
awatch <表达式>:表达式被访问、改变是暂停执行
rwatch <表达式>:表达式被访问时暂停执行
通过“generate-core-file”生成core.xxxx转储文件。
然后gdb ./main ./core.xxxx查看恢复的现场。
[root@mysqldb ~]# gdb -p 7806
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-114.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
Attaching to process 7806
Reading symbols from /usr/local/mysql-5.7.26-linux-glibc2.12-x86_64/bin/mysqld...done.
Reading symbols from /lib64/libpthread.so.0...(no debugging symbols found)...done.
[New LWP 7835]
[New LWP 7834]
[New LWP 7833]
[New LWP 7832]
[New LWP 7831]
[New LWP 7830]
[New LWP 7829]
[New LWP 7828]
[New LWP 7827]
[New LWP 7826]
[New LWP 7825]
[New LWP 7824]
[New LWP 7823]
[New LWP 7822]
[New LWP 7821]
[New LWP 7818]
[New LWP 7817]
[New LWP 7816]
[New LWP 7815]
[New LWP 7814]
[New LWP 7813]
[New LWP 7812]
[New LWP 7811]
[New LWP 7810]
[New LWP 7809]
[New LWP 7808]
[New LWP 7807]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Loaded symbols for /lib64/libpthread.so.0
Reading symbols from /lib64/libaio.so.1...Reading symbols from /lib64/libaio.so.1...(no debugging symbols found)...done.
(no debugging symbols found)...done.
Loaded symbols for /lib64/libaio.so.1
Reading symbols from /lib64/libnuma.so.1...Reading symbols from /lib64/libnuma.so.1...(no debugging symbols found)...done.
(no debugging symbols found)...done.
Loaded symbols for /lib64/libnuma.so.1
Reading symbols from /lib64/libcrypt.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib64/libcrypt.so.1
Reading symbols from /lib64/libdl.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/libdl.so.2
Reading symbols from /lib64/librt.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib64/librt.so.1
Reading symbols from /lib64/libstdc++.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib64/libstdc++.so.6
Reading symbols from /lib64/libm.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib64/libm.so.6
Reading symbols from /lib64/libgcc_s.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib64/libgcc_s.so.1
Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib64/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
Reading symbols from /lib64/libfreebl3.so...Reading symbols from /lib64/libfreebl3.so...(no debugging symbols found)...done.
(no debugging symbols found)...done.
Loaded symbols for /lib64/libfreebl3.so
Reading symbols from /lib64/libnss_files.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/libnss_files.so.2
Reading symbols from /usr/local/mysql57/lib/plugin/semisync_master.so...done.
Loaded symbols for /usr/local/mysql57/lib/plugin/semisync_master.so
Reading symbols from /usr/local/mysql57/lib/plugin/semisync_slave.so...done.
Loaded symbols for /usr/local/mysql57/lib/plugin/semisync_slave.so
0x00007f449b97cbed in poll () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.17-292.el7.x86_64 libaio-0.3.109-13.el7.x86_64 libgcc-4.8.5-39.el7.x86_64 libstdc++-4.8.5-39.el7.x86_64 nss-softokn-freebl-3.36.0-5.el7_5.x86_64 numactl-libs-2.0.9-7.el7.x86_64
(gdb)
# 此mysql源码sql_insert.cc的423行的函数Sql_cmd_insert::mysql_insert
(gdb) b Sql_cmd_insert::mysql_insert
Breakpoint 1 at 0xea1035: file /export/home/pb2/build/sb_0-33648028-1555164244.06/mysql-5.7.26/sql/sql_insert.cc, line 422.
在另一个session2中登录数据库,发现无法登录,hung住了,在gdb中执行next(执行下一步代码),可以看到在socket_connection.cc源码第859行无法继续,代码大致是说要获取系统的socket,还有一些监听信息,由于太多了,直接在gdb中执行continue(到下一个可执行的代码),此时session2已经登录成功。
在session2执行select等非insert操作一切是正常的。
如果执行insert,则会话又被hung了。可以单步输入n结合bt,查看具体执行过程
pmap内存分析工具,可以查看进程的内存映像信息。常用来检查是否存在内存泄露 问题
-x extended Show the extended format. 显示扩展格式
-d device Show the deviceformat. 显示设备格式
-q quiet Do not display some header/footerlines. 不显示头尾行
-V show version Displays version of program. 显示版本
mapped 表示该进程映射的虚拟地址空间大小,也就是该进程预先分配的虚拟内存大小,即ps出的vsz
writeable/private 表示进程所占用的私有地址空间大小,也就是该进程实际使用的内存大小
shared 表示进程和其他进程共享的内存大小
内存泄露检测方法:
A)VIRT/VSZ或者writeable/private (pmap –d输出)如果在做重复的操作过程中一直保持稳定增长,那么一定有内存泄露。
B) RSS只能作为参考,不能用来确定是否有内存泄露。
while true; do pmap -d 4027 | tail -1; sleep 2; done
pstack用来跟踪进程栈,这个命令在排查进程问题时非常有用,比如我们发现一个服务一直处于work状态(如假死状态,好似死循环),使用这个命令就能轻松定位问题所在;可以在一段时间内,多执行几次pstack,若发现代码栈总是停在同一个位置,那个位置就需要重点关注,很可能就是出问题的地方;
pt-pmp可以对生成的pstack输出文件进行排序分析,也可以直接对进程进行堆栈排序分析。
pt-pmp对堆栈信息排序:
pt-pmp pstack.info | less
也可以直接执行pt-pmp:
pt-pmp --pid 4522
strace常用来跟踪进程执行时的系统调用和所接收的信号。 在Linux世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通过系统调用访问硬件设备。strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间。
strace可以跟踪正在运行的进程,或可以加执行命令进行跟踪。
选项 |
说明 |
-f |
跟踪目标进程,以及目标进程创建的所有子进程(fork, vfork and clone) |
-ff |
结果-o一起使用,把strace输出到filename.pid,pid线程ID |
-o |
把strace的输出单独写到指定的文件 |
-F |
已降级参数,功能同-f |
-p |
指定要跟踪的进程pid, 要同时跟踪多个pid, 重复多次-p选项即可 |
-s |
当系统调用的某个参数是字符串时,最多输出指定长度的内容,默认是32个字节 |
-T |
显示每次系统调用所花费的时间 |
-tt |
在每行输出的前面,显示毫秒级别的时间 |
-v |
对于某些相关调用,把完整的环境变量,文件stat结构等打出来 |
-e |
控制要跟踪的事件和跟踪行为,比如指定要跟踪的系统调用名称 |
-e trace=file 跟踪和文件访问相关的调用(参数中有文件名)
-e trace=process 和进程管理相关的调用,比如fork/exec/exit_group
-e trace=network 和网络通信相关的调用,比如socket/sendto/connect
-e trace=signal 信号发送和处理相关,比如kill/sigaction
-e trace=desc 和文件描述符相关,比如write/read/select/epoll等
-e trace=ipc 进程见同学相关,比如shmget等
strace -tt -T -f -e trace=file -o /data/log/strace.log -s 1024 ./nginx
mysqld_pid=4027
strace -f -F -ff -o mysqld-strace -s 1024 -p $mysqld_pid #此会每个线程生成一个文件,文件名后缀为OS Thread ID.
ls mysqld-strace.* |xargs grep -ni "select"
perf是Linux下的一款性能分析工具,能够进行函数级与指令级的热点查找。
Linux性能计数器是一个新的基于内核的子系统,它提供一个性能分析框架,比如硬件(CPU、PMU(Performance Monitoring Unit))功能和软件(软件计数器、tracepoint)功能。
通过perf,应用程序可以利用PMU、tracepoint和内核中的计数器来进行性能统计。它不但可以分析制定应用程序的性能问题(per thread),也可以用来分析内核的性能问题,当然也可以同时分析应用程序和内核,从而全面理解应用程序中的性能瓶颈。
使用perf,可以分析程序运行期间发生的硬件事件,比如instructions retired、processor clock cycles等;也可以分析软件时间,比如page fault和进程切换。
1 |
annotate |
。 |
2 |
archive |
根据数据文件记录的build-id,将所有被采样到的elf文件打包。利用此压缩包,可以再任何机器上分析数据文件中记录的采样数据。 |
3 |
bench |
perf中内置的benchmark,目前包括两套针对调度器和内存管理子系统的benchmark。 |
4 |
buildid-cache |
管理perf的buildid缓存,每个elf文件都有一个独一无二的buildid。buildid被perf用来关联性能数据与elf文件。 |
5 |
buildid-list |
列出数据文件中记录的所有buildid。 |
6 |
diff |
对比两个数据文件的差异。能够给出每个符号(函数)在热点分析上的具体差异。 |
7 |
evlist |
列出数据文件perf.data中所有性能事件。 |
8 |
inject |
该工具读取perf record工具记录的事件流,并将其定向到标准输出。在被分析代码中的任何一点,都可以向事件流中注入其它事件。 |
9 |
kmem |
针对内核内存(slab)子系统进行追踪测量的工具 |
10 |
kvm |
用来追踪测试运行在KVM虚拟机上的Guest OS。 |
11 |
list |
列出当前系统支持的所有性能事件。包括硬件性能事件、软件性能事件以及检查点。 |
12 |
lock |
分析内核中的锁信息,包括锁的争用情况,等待延迟等。 |
13 |
mem |
内存存取情况 |
14 |
record |
收集采样信息,并将其记录在数据文件中。随后可通过其它工具对数据文件进行分析。 |
15 |
report |
读取perf record创建的数据文件,并给出热点分析结果。 |
16 |
sched |
针对调度器子系统的分析工具。 |
17 |
script |
执行perl或python写的功能扩展脚本、生成脚本框架、读取数据文件中的数据信息等。 |
18 |
stat |
执行某个命令,收集特定进程的性能概况,包括CPI、Cache丢失率等。 |
19 |
test |
perf对当前软硬件平台进行健全性测试,可用此工具测试当前的软硬件平台是否能支持perf的所有功能。 |
20 |
timechart |
针对测试期间系统行为进行可视化的工具 |
21 |
top |
类似于linux的top命令,对系统性能进行实时分析。 |
22 |
trace |
关于syscall的工具。 |
23 |
probe |
用于定义动态检查点。 |
sudo perf record -a -F 99 -g -p $(pgrep -x mysqld) -- sleep 60
Warning:
PID/TID switch overriding SYSTEM
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.081 MB perf.data ]
参数:-F 99Hz采集,它的执行频率是 99Hz(每秒99次)
sudo perf record -a -F 99 -g -p $(pgrep -x mysqld)
sudo perf script > perf.script
安装FlameGraph(该工具也可以分析如dtrace、gdb等等生成的trace)
git clone https://github.com/brendangregg/FlameGraph.git
./FlameGraph/stackcollapse-perf.pl perf.script | ./FlameGraph/flamegraph.pl > flamegraph.svg
perf top -p `pidof mysqld`
第一列:符号引发的性能事件的比例,默认指占用的cpu周期比例。
第二列:符号所在的DSO(Dynamic Shared Object),可以是应用程序、内核、动态链接库、模块。
第三列:DSO的类型。[.]表示此符号属于用户态的ELF文件,包括可执行文件与动态链接库)。[k]表述此符号属于内核或模块。
第四列:符号名。有些符号不能解析为函数名,只能用地址表示。
SystemTap、dtrace等工具相对使用较复杂,此不介绍
pldd :可查看程序依赖的共享库信息