博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[转] 关于《Linux常用调试和性能分析工具》的学习笔记
阅读量:5774 次
发布时间:2019-06-18

本文共 3457 字,大约阅读时间需要 11 分钟。

hot3.png

前言

好久没写博客了,最近,上了一门公司内部的课程,觉得收获很大,所以,在博客写写,当成一个学习笔记。

首先Linux下的程序调试,这里只针对C/C++的程序,讲讲如何在编译阶段和运行阶段调试程序。后面将简单介绍一下几大性能分析工具。

一、编译阶段调试工具

与Javascript和Python不同,C/C++是编译语言,需要编译成目标文件,再将目标文件链接成一个可执行文件。

说到这里,就得说说Linux的ELF文件格式,ELF(Executable and Linkable Format)即可执行连接文件格式(注:window编译器会一般生成coff格式),是Linux,SVR4和Solaris2.0默认的目标文件格式,目前标准接口委员会TIS已将ELF标准化为一种可移植的目标文件格式,运行于32-bit Intel体系微机上,可与多种操作系统兼容。分析elf文件有助于理解一些重要的系统概念,例如程序的编译和链接,程序的加载和运行等。

ELF有三种格式:

可重定位文件:用户和其他目标文件一起创建可执行文件或者共享目标文件,例如lib*.a文件。

可执行文件:用于生成进程映像,载入内存执行,例如编译好的可执行文件a.out。
共享目标文件:用于和其他共享目标文件或者可重定位文件一起生成elf目标文件或者和执行文件一起创建进程映像,例如lib*.so文件。

这里就不展开了,有兴趣的同学可以了解一下,Linux下,默认编译好的a.out,就是ELF格式的文件。1. readelf 和 objdump

可以通过接下来这两个工具,readelf和objdump都可以从二进制文件a.out中读取相应的信息并显示。
至于两者的区别 stackoverflow有人提到。

#查看a.out的文件头部readelf -h a.out#查看a.out所有内容readelf -a a.out#查看a.out的反汇编代码objdump -S a.out

详细用法:

2.nm

用来列出目标文件的符号清单,这其中会出现符号的类型,符号的类型是以一个字母的形式显示的,小写字母表示这个符号是本地(local)的,而大写字母则表示这个符号是全局的(global,externel)。一般来说,类型有一下几种:T、D、B、U、W。各自的含义如下:T表示在代码段中定义的一般变量符号;D表示时初始化过的数据段;B表示初始化的数据段;U表示没有定义的,在这个库里面使用了,但是在其他库中定义的符号;W,weak的缩写,表示如果其他函数库中也有对这个符号的定义,则其他符号的定义可以覆盖这个定义。

当使用C/C++混编的程序,有时候,会发现找不到定义的情况,当使用了nm检查一下符号表,就一目了然了

#查看符号表函数签名nm -C ./a.out

3.strings

获取二进制文件里面的字符串常量,对于检查固定加密key值和某些常量的值十分有用,例如有时候一些变量,在测试环境和现网环境中,需要经常变化,里面一些变量,需要strings检查确认一下,是否为那个变量。

#在a.out二进制文件中,查找key字段strings a.out | grep “key="#在ls中,查找“http:”对应的信息strings /bin/ls | grep "http:"

4.strip

通过除去绑定程序和符号调试程序使用的信息,减少文件的大小,这个命令十分有用,可以帮助我们清除程序中不必要的标识符和调试信息,可以大大减少文件的大小,而不会影响使用,但是,strip之后的程序,就无法使用gdb进行调试了。所以千万不要对库文件使用。

#清除a.out的符号表和行号信息。strip a.out

二、运行阶段调试工具

1.gdb

大名鼎鼎的GDB,是程序运行时调试的一把利器,没有之一,如果要展开介绍,可以写多一篇博文了,这里简单带过,介绍一下。

首先,gdb调试的程序,需要在使用gcc命令编译的时候,加入-g
其中有几个很有用的命令:
1 bt:显示程序栈,当发现错误的时候,这个命令这个让你迅速定位到问题的所在。
2 c:继续执行
3 list:显示当前程序所断点位置的上下文,或者上次list位置之后的程序代码
4 step:进入函数内部,跟进函数

gdb对于使用C++做CGI开发,也有很重要作用,当前台需要通过HTTP协议传一个文件的时候,单单模拟POST已经无法满足了,所以,最简单的方法可以通过gdb来调试正在运行的进程。

可以从页面发起一个请求,当后台正在执行CGI的时候,马上使用 ps -ef | egrep "a.cgi"
找到进程号PID,然后通过 gdb -p PID 来跟踪进程。或者也可以通过进入gdb后,通过attach PID来调试正在运行,
进入之后,可以通过bt,或者list来确定当前的运行位置。
当调试完毕,可以通过detach来断开连接,让被调试的进程正常运行。
之前,遇到一个bug,死活调试不出是什么原因导致,多加一个参数,程序就错误,看代码也没看出所以然,最后,还是通过这个方法,定位到是一个指针被重复释放了两次而导致的。当然如果,程序很快就执行完,可以通过在程序代码中,调用sleep()函数,延缓执行时间。
gdb 的详细方法,可以Man 或者 Info

2.pmap

当想查看进程的内存分布情况或者目标文件各个段的大小,可以使用这个命令,这个命令与直接通过vim /proc/PID/maps是基本一样的。

3.Ldd

查看程序用到的动态链接库,这个命令其实是一个shell命令,显示出来的所以来的库文件,其实都是一个软连接。

三、性能分析工具

1.vmstat

vmstat是一个十分有用的Linux系统监控工具,使用vmstat命令可以得到关于进程、内存、内存分页、堵塞IO、traps及CPU活动的信息。

1 #每秒刷新一次结果
2 vmstat 1

2.strace

显示程序调用的系统调用 这里需要区分一下系统调用和C库函数:系统调用通常用于底层文件访问(low-level file access),例如在驱动程序中对设备文件的直接访问。

系统调用是操作系统相关的,因此一般没有跨操作系统的可移植性。
C库函数提供的文件操作函数如fopen, fread, fwrite, fclose, fflush, fseek等 库函数调用通常用于应用程序中对一般文件的访问。
库函数调用是系统无关的,因此可移植性好。

3.ltrace

显示程序调用的动态库函数
1 ltarce -p PID

4.sar

系统监控工具 类似vmstat

1 #检查IO使用情况
2 sar -d 1 100
3 #检查网卡使用情况
4 sar -n DEV 1 100
5 #检查CPU使用情况
6 sar -u 1 100

5.iostat

监控IO性能工具

1 #1秒显示一次IO信息
2 iostat -x 1

6.top

这个命令,大家已经十分熟悉了,动态显示系统当前的进程和其他状况

7.gprof

显示各个函数的执行时间

必须在gcc 加上-pg -g
如果对C库进行性能分析,gcc -lc_p
程序必须通过正常途径退出,不能kill -9
千万不能先使用上文所介绍的Strip,那样就无法分析各个函数执行。
1 gprof -b ./a.out

8.time

显示程序执行时间、其中用户态时间、其中内核态时间

但只能跟踪父进程

10.netstat

监控网卡状态, 其中两个重要的表项 Send-Q 接受队列 和 Recv-Q 发送队列 ,Recv-Q:Socket接收缓存,满了(比如CPU太忙)就会丢包

1 #显示TCP协议的连接情况
2 netstat -t
3 #显示udp协议的连接情况
4 netstat -u
5 #显示所有进程和监听端口
6 netstat -lpn
7 #统计udp包
8 netstat -su
9 #实时显示upd包的信息
10 watch netstat -su

11.Free

显示系统内存使用情况

命令就介绍完了,这只是一个入门的命令介绍,如果想深入可以通过Info,Man 和 Google,当然,最重要的还是自己要多动手。

 

转载于:https://my.oschina.net/u/2007478/blog/968483

你可能感兴趣的文章
多线程-ReentrantLock
查看>>
数据库架构
查看>>
【转】图文详解硬盘安装fedora
查看>>
转:LR和QTP的区别
查看>>
Loadrunner Get&Post方法性能测试脚本解析
查看>>
BZOJ 1833 数位DP
查看>>
three.js之创建一个几何体
查看>>
抽象类与接口类
查看>>
浅说《测试用例》----给测试新手的
查看>>
数据结构之链表与哈希表
查看>>
(一)Builder(建造者)模式
查看>>
[转]基于NodeJS的14款Web框架
查看>>
IIS7/8下提示 HTTP 错误 404.13 - Not Found 请求筛选模块被配置为拒绝超过请求内容长度的请求...
查看>>
http返回状态码含义
查看>>
提高网站页面加载速度的方法
查看>>
分布式缓存的面试题2
查看>>
响应式网站对百度友好关键
查看>>
洛谷P2179 骑行川藏
查看>>
暑假周总结三
查看>>
我的Android进阶之旅------>Handlerr.removeCallbacksAndMessages(null)的作用
查看>>