linux C/C++ 后端服务问题排查(gdb, pstack,valgrind)

        在linux上运行的c/c++程序,一般是没有界面的,一般都需要打印运行日志,通过日志来定位问题。但是日志不是万能的,有时候日志没有输出我们的想要的信息,如果增加日志还要程序重新编译部署发布,如果是生产上的服务,为了排查一个问题就要发布版本,那这肯定是得不偿失的。除了日志,linux上我们还有很多手段去帮助我们排查程序问题,就是linux提供了很多有用的命令行工具让我们查找问题。这里我总结了经常使用的几个命令的用法,gdb, pstack,valgrind。

gbd命令

gdb命令就是我们调试程序用的,其实跟windows上的我们常用的visual studio调试是一样的,只是windows上的调试都是可视化的,直接在IDE上启动程序,然后在文件上打断点调试,用鼠标在变量上面一停就能看到变量的值,很方便。但是在linux下,调试的门槛感觉就高多了,黑洞洞的窗口,让人感觉无从下手。gdb的功能很强大,很多,我只介绍一些比较重要的使用方法。

(1)直接调试

gdb exefile

以上直接使用gdb进行调试,但是如果可执行文件需要启动参数才能正常运行的的话,上面的命令就导致程序执行不正常分支。此时应该按下面的步骤启动

(2)调试带参数的可执行程序

使用命令:gdb --args exefile arg1 arg2

上面的命令就会启动gdb,并给可执行文件设置启动参数,但是gdb启动后没有马上运行exefile,而是等待命令,此时你需要输入start或者run命令,gdb才会运行exefile的代码.程序运行的过程中,你是无法输入gdb命令的,此时你可以使用Ctrl+c,中断运行中的程序,此时你就可以输入gdb命令了,比如打印变量值,设置断点等等

(3)使用gdb查看core文件

gdb 程序名 corefile

使用参数-tui,启动可以直接将屏幕分成两个部分,上面显示源代码,比用list方便多了。这时候使用上下方向键可以查看源代码,想要命令行使用上下键就用[Ctrl]n和[Ctrl]p.

其实查看core文件和实际调试正在运行的程序都差不多,可以查看堆栈信息,可以查看变量的值,因为这些信息都会保存在core文件里了

(4)已经运行的程序,使用gdb attach进入调试

当程序已经处于运行状态,需要使用gdb调试可以使用attach命令:

gdb attach 进程id

attach上去之后就可以调试了

(5)gdb调试多线程

让程序停在某个断点,或者中断执行中的程序,就可以输入gdb命令进行多线程的调试。

1、首先查看线程信息:info threads

下面是输出的信息:

  5    Thread 0x2aed315c7700 (LWP 4998) "camera_pro" 0x00002aecebe3156d in nanosleep () from /lib64/libc.so.6

  4    Thread 0x2aed317c8700 (LWP 4999) "camera_pro" 0x00002aecec144d42 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0

  3    Thread 0x2aed319c9700 (LWP 5000) "camera_pro" 0x00002aecebe3156d in nanosleep () from /lib64/libc.so.6

  2    Thread 0x2aed31bca700 (LWP 5001) "camera_pro" 0x00002aecebe6b183 in epoll_wait () from /lib64/libc.so.6

* 1    Thread 0x2aecea6b3040 (LWP 4972) "camera_pro" 0x00002aecebe5bc8d in read () from /lib64/libc.so.6

线程id为LWP后面的数字,其中前面的*号表示当前所在线程

2、切换线程: thread Id

3、将程序的执行流锁定在某个线程: set scheduler-locking on/off

4、显示当前的scheduler-locking 状态:show scheduler-locking

5、查看所有线程的堆栈信息:thread apply all bt 这个是终极大招,基本上程序跑到哪里都能清清楚楚的看到,只要你编译的是-d的版本,你还可以查看所有的变量值

pstack命令

pstack命令也和gdb调试很像,可以直接查看堆栈,但是功能远没有gdb那么强大,这个命令只有查看堆栈信息这个功能。但是我们有时候只需要堆栈信息。

查看某个进程的堆栈调用信息,直接后面跟进程id就可以

Usage: pstack <process-id>

例如:

[root@localhost ~]# ps -ef | grep redis

root      1363     1  0 11月10 ?      00:00:40 redis-server *:6379

root     26454 25948  0 15:12 pts/0    00:00:00 grep --color=auto redis

[root@localhost ~]# pstack 1363

Thread 3 (Thread 0x7fed01fff700 (LWP 1366)):

#0  0x00007fed09431995 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0

#1  0x00000000004504d6 in bioProcessBackgroundJobs (arg=0x0) at bio.c:164

#2  0x00007fed0942de25 in start_thread () from /lib64/libpthread.so.0

#3  0x00007fed09157bad in clone () from /lib64/libc.so.6

Thread 2 (Thread 0x7fed017fe700 (LWP 1367)):

#0  0x00007fed09431995 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0

#1  0x00000000004504d6 in bioProcessBackgroundJobs (arg=0x1) at bio.c:164

#2  0x00007fed0942de25 in start_thread () from /lib64/libpthread.so.0

#3  0x00007fed09157bad in clone () from /lib64/libc.so.6

Thread 1 (Thread 0x7fed09d5b780 (LWP 1363)):

#0  0x00007fed09158183 in epoll_wait () from /lib64/libc.so.6

#1  0x0000000000418d73 in aeApiPoll (tvp=<optimized out>, eventLoop=0x7fed020581a0) at ae_epoll.c:114

#2  aeProcessEvents (eventLoop=eventLoop@entry=0x7fed020581a0, flags=flags@entry=3) at ae.c:400

#3  0x000000000041919b in aeMain (eventLoop=0x7fed020581a0) at ae.c:455

#4  0x0000000000417ef7 in main (argc=<optimized out>, argv=0x7fff5dd1bc08) at redis.c:3382

valgrind命令

valgrind也是一个很强大的工具,用来查找内存泄漏和程序崩溃问题。

(1)安装valgrind程序

可以用源码安装

wget https://fossies.org/linux/misc/valgrind-3.15.0.tar.bz2

tar -jxvf valgrind-3.15.0.tar.bz2

cd valgrind-3.15.0

./configure

make

sudo make install

centos下也可以直接使用yum命令直接安装

yum install valgrind

(2)准备需要调试的程序

程序在编译的时候一般需要使用 -O0不进行优化-g带调试信息,这样才能看到具体是代码中的哪一行有内存泄漏

(3)valgrind的使用

调用 Valgrind 的通用格式是:valgrind [valgrind-options] your-prog [your-progoptions]

一般检查内存泄漏的都需要加--leak-check=full参数,例如:

valgrind --leak-check=full --tool=memcheck ./vg

valgrind是在程序执行结束后才打印输出信息,输出信息样例如下:

[root@localhost gittest]# valgrind --leak-check=full ./vg

==2447== Memcheck, a memory error detector

==2447== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.

==2447== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info

==2447== Command: ./vg

==2447==

finish

6

==2447==

==2447== HEAP SUMMARY:

==2447==     in use at exit: 4 bytes in 1 blocks

==2447==   total heap usage: 4 allocs, 3 frees, 72,746 bytes allocated

==2447==

==2447== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1

==2447==    at 0x4C29F73: malloc (vg_replace_malloc.c:309)

==2447==    by 0x400B63: fun() (valgrindtest.cpp:16)

==2447==    by 0x400B81: main (valgrindtest.cpp:22)

==2447==

==2447== LEAK SUMMARY:

==2447==    definitely lost: 4 bytes in 1 blocks

==2447==    indirectly lost: 0 bytes in 0 blocks

==2447==      possibly lost: 0 bytes in 0 blocks

==2447==    still reachable: 0 bytes in 0 blocks

==2447==         suppressed: 0 bytes in 0 blocks

==2447==

==2447== For lists of detected and suppressed errors, rerun with: -s

==2447== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

其中by 0x400B63: fun() (valgrindtest.cpp:16)这句就是指明明确的内存泄漏代码所在的行号

valgrind也可以检测内存越界的问题

使用未初始化的内存也可以检测出来

使用类似strncp()这样的函数,导致内存重叠也可以检测出来

使用--log-file=filepath 来指定valgrind的输出信息:valgrind --leak-check=full --log-file=./vg.log ./vg

搜索“definitely lost”寻找确定内存泄漏的地方

        

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值