【做减法】Linux工具快速教程 - 高级篇

1. 程序构建

一般源代码提供的程序安装需要通过配置、编译、安装三个步骤;
1. 配置做的工作主要是检查当前环境是否满足要安装软件的依赖关系,以及设置程序安装所需要的初始化信息,比如安装路径,需要安装哪些组件;配置完成,会生成makefile文件供第二步make使用;
2. 编译是对源文件进行编译链接生成可执行程序;
3. 安装做的工作就简单多了,就是将生成的可执行文件拷贝到配置时设置的初始路径下;

1.1 配置

查询可用的配置选项: ./configure --help
配置路径: ./configure --prefix=/usr/local/snmp
–prefix是配置使用的最常用选项,设置程序安装的路径;

1.2 编译

编译使用make编译: make -f myMakefile

通过-f选项显示指定需要编译的makefile;如果待使用makefile文件在当前路径,且文件名为以下几个,则不用显示指定: makefile Makefile

makefile编写的要点:
必须满足第一条规则,满足后停止
除第一条规则,其他无顺序

makefile中的全局自变量

  • $@目标文件名
  • @^所有前提名,除副本
  • @+所有前提名,含副本
  • @<一个前提名
  • @?所有新于目标文件的前提名
  • @*目标文件的基名称

使用CMake,能够使程序员从复杂的编译连接过程中解脱出来。它使用一个名为 CMakeLists.txt 的文件来描述构建过程,可以生成标准的构建文件

makefile编译过程中所依赖的非标准库和头文件路径需要显示指明:

CPPFLAGS -I标记非标准头文件存放路径
LDFLAGS -L标记非标准库存放路径

如果CPPFLAGS和LDFLAGS已在用户环境变量中设置并且导出(使用export关键字),就不用再显示指定;

make -f myMakefile LDFLAGS='-L/var/xxx/lib -L/opt/mysql/lib'
CPPFLAGS='-I/usr/local/libcom/include -I/usr/local/libpng/include'

警告:链接多库时,多个库之间如果有依赖,需要注意书写的顺序,右边是左边的前提;

g++编译:g++ -o unixApp unixApp.o a.o b.o
选项说明:
-o:指明生成的目标文件
-g:添加调试信息
-E: 查看中间文件

查询应用程序需要链接的库: ldd myprogrammer

1.3 安装

安装做的工作就简单多了,就是将生成的可执行文件拷贝到配置时设置的初始路径下: make install
其实 install 就是makefile中的一个规则,打开makefile文件后可以查看程序安装的所做的工作;

2 程序调试

2.1 GDB 程序交互调试

以下从一个完整的调试过程简单说明最基本的几个命令;

gdb programmer # 启动gdb
break main # 设置断点
run # 运行调试程序
next # 单步调试
print var1 #在调试过程中,我们需要查看当前某个变量值的时候,使用print 命令打印该值
list # 显示当前调试处的源代码
info b # 显示当前断点设置情况

2.2 pstack 跟踪栈空间

pstack是一个脚本工具,可显示每个进程的栈跟踪。pstack 命令必须由相应进程的属主或 root 运行。其核心实现就是使用了gdb以及thread apply all bt命令
pstrack <program-pid>

2.3 strace 分析系统调用

strace常用来跟踪进程执行时的系统调用和所接收的信号。在Linux世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通过系统调用访问硬件设备。strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间。
strace -o output.txt -T -tt -e trace=all -p 28979

2.4 objdump

ogjdump工具用来显示二进制文件的信息,就是以一种可阅读的格式让你更多地了解二进制文件可能带有的附加信息。objdump -d myprogrammer

2.5 readelf

这个工具和objdump命令提供的功能类似,但是它显示的信息更为具体,并且它不依赖BFD库(BFD库是一个GNU项目,它的目标就是希望通过一种统一的接口来处理不同的目标文件) readelf -all a.out

2.6 size

size 用来查看程序运行时各个段的实际内存占用:size a.out

2.7 strings

一个文件中包含二进制数据和文本数据,如果只需要查看其文本信息,使用这个命令就很方便;过滤掉非字符数据,将文本信息输出:strings <objfile>

2.8 fuser

显示所有正在使用着指定的file, file system 或者 sockets的进程信息;
fuser -m -u redis-server

使用了-m和-u选项,用来查找所有正在使用redis-server的所有进程的PID以及该进程的OWNER;

2.8 xxd

以十六进制方式显示文件,只显示文本信息:xxd a.out

3 性能优化

3.1 分析系统瓶颈

进入交互模式后:
•输入M,进程列表按内存使用大小降序排序,便于我们观察最大内存使用者使用有问题(检测内存泄漏问题);
•输入P,进程列表按CPU使用大小降序排序,便于我们观察最耗CPU资源的使用者是否有问题;

top第三行显示当前系统的,其中有两个值很关键:
•%id:空闲CPU时间百分比,如果这个值过低,表明系统CPU存在瓶颈;
•%wa:等待I/O的CPU时间百分比,如果这个值过高,表明IO存在瓶颈;

3.2 分析内存瓶颈

查看内存是否存在瓶颈,使用top指令看比较麻烦,而free命令更为直观:
top工具显示了free工具的第一行所有信息,但真实可用的内存,还需要自己计算才知道; 系统实际可用的内存为free工具输出第二行的free+buffer+cached;也就是第三行的free值

3.3 分析I/O瓶颈

如果IO存在性能瓶颈,top工具中的%wa会偏高;进一步分析使用iostat工具:iostat -d -x -k 1 1

  • 如果%iowait的值过高,表示硬盘存在I/O瓶颈。

  • 如果 %util 接近 100%,说明产生的I/O请求太多,I/O系统已经满负荷,该磁盘可能存在瓶颈。

  • 如果 svctm 比较接近 await,说明 I/O 几乎没有等待时间;
  • 如果 await 远大于 svctm,说明I/O 队列太长,io响应太慢,则需要进行必要优化。
  • 如果avgqu-sz比较大,也表示有大量io在等待。

3.4 分析进程调用

pstack用来跟踪进程栈,这个命令在排查进程问题时非常有用,比如我们发现一个服务一直处于work状态(如假死状态,好似死循环),使用这个命令就能轻松定位问题所在;可以在一段时间内,多执行几次pstack,若发现代码栈总是停在同一个位置,那个位置就需要重点关注,很可能就是出问题的地方;

示例:查看bash程序进程栈:ps -fe| grep bash

3.5 其它工具

调试内存泄漏的工具valgrind
OProfile 也是 Linux 平台上的一个功能强大的性能分析工具,

4 工具简介

4.1 gdb交互命令

启动gdb后,进入到交互模式,通过以下命令完成对程序的调试;注意高频使用的命令一般都会有缩写,熟练使用这些缩写命令能提高调试的效率;

运行
•run:简记为 r ,其作用是运行程序,当遇到断点后,程序会在断点处停止运行,等待用户输入下一步的命令。
•continue (简写c ):继续执行,到下一个断点处(或运行结束)
•next:(简写 n),单步跟踪程序,当遇到函数调用时,也不进入此函数体;此命令同 step 的主要区别是,step 遇到用户自定义的函数,将步进到函数中去运行,而 next 则直接调用函数,不会进入到函数体内。
•step (简写s):单步调试如果有函数调用,则进入函数;与命令n不同,n是不进入调用的函数的
•until:当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体。
•until+行号: 运行至某行,不仅仅用来跳出循环
•finish: 运行程序,直到当前函数完成返回,并打印函数返回时的堆栈地址和返回值及参数值等信息。
•call 函数(参数):调用程序中可见的函数,并传递“参数”,如:call gdb_test(55)
•quit:简记为 q ,退出gdb

查询运行信息
•where/bt :当前运行的堆栈列表;
•bt backtrace 显示当前调用堆栈
•up/down 改变堆栈显示的深度
•set args 参数:指定运行时的参数
•show args:查看设置好的参数
•info program: 来查看程序的是否在运行,进程号,被暂停的原因

4.2 ldd 查看程序依赖库

用来查看程式运行所需的共享库,常用来解决程式因缺少某个库文件而不能运行的一些问题。

第一列:程序需要依赖什么库
第二列: 系统提供的与程序需要的库所对应的库
第三列:库加载的开始地址

ldd不是个可执行程式,而只是个shell脚本;
ldd显示可执行模块的dependency的工作原理,其实质是通过ld-linux.so(elf动态库的装载器)来实现的。ld-linux.so模块会先于executable模块程式工作,并获得控制权,因此当上述的那些环境变量被设置时,ld-linux.so选择了显示可执行模块的dependency。

4.3 lsof 一切皆文件

命令参数

  • -a 列出打开文件存在的进程
  • -c<进程名> 列出指定进程所打开的文件
  • -g 列出GID号进程详情
  • -d<文件号> 列出占用该文件号的进程
  • +d<目录> 列出目录下被打开的文件
  • +D<目录> 递归列出目录下被打开的文件
  • -n<目录> 列出使用NFS的文件
  • -i<条件> 列出符合条件的进程。(4、6、协议、:端口、 @ip )
  • -p<进程号> 列出指定进程号所打开的文件
  • -u 列出UID号进程详情
  • -h 显示帮助信息
  • -v 显示版本信息

lsof输出各列信息的意义如下:

  • COMMAND:进程的名称
  • PID:进程标识符
  • PPID:父进程标识符(需要指定-R参数)
  • USER:进程所有者
  • PGID:进程所属组
  • FD:文件描述符,应用程序通过文件描述符识别该文件。如cwd、txt等:

(1)cwd:表示current work dirctory,即:应用程序的当前工作目录,这是该应用程序启动的目录,除非它本身对这个目录进行更改
(2)txt :该类型的文件是程序代码,如应用程序二进制文件本身或共享库,如上列表中显示的 /sbin/init 程序
(3)lnn:library references (AIX);
(4)er:FD information error (see NAME column);
(5)jld:jail directory (FreeBSD);
(6)ltx:shared library text (code and data);
(7)mxx :hex memory-mapped type number xx.
(8)m86:DOS Merge mapped file;
(9)mem:memory-mapped file;
(10)mmap:memory-mapped device;
(11)pd:parent directory;
(12)rtd:root directory;
(13)tr:kernel trace file (OpenBSD);
(14)v86 VP/ix mapped file;
(15)0:表示标准输出
(16)1:表示标准输入
(17)2:表示标准错误
一般在标准输出、标准错误、标准输入后还跟着文件状态模式:r、w、u等
(1)u:表示该文件被打开并处于读取/写入模式
(2)r:表示该文件被打开并处于只读模式
(3)w:表示该文件被打开并处于
(4)空格:表示该文件的状态模式为unknow,且没有锁定
(5)-:表示该文件的状态模式为unknow,且被锁定
同时在文件状态模式后面,还跟着相关的锁
(1)N:for a Solaris NFS lock of unknown type;
(2)r:for read lock on part of the file;
(3)R:for a read lock on the entire file;
(4)w:for a write lock on part of the file;(文件的部分写锁)
(5)W:for a write lock on the entire file;(整个文件的写锁)
(6)u:for a read and write lock of any length;
(7)U:for a lock of unknown type;
(8)x:for an SCO OpenServer Xenix lock on part of the file;
(9)X:for an SCO OpenServer Xenix lock on the entire file;
(10)space:if there is no lock.

  • TYPE:文件类型,如DIR、REG等,常见的文件类型:
  • DEVICE:指定磁盘的名称
  • SIZE:文件的大小
  • NODE:索引节点(文件在磁盘上的标识)
  • NAME:打开文件的确切名称

列出某个程序进程所打开的文件信息 lsof -c mysql
通过某个进程号显示该进程打开的文件 lsof -p 11968
列出所有的网络连接 lsof -i
列出所有tcp 网络连接信息 lsof -i tcp
列出谁在使用某个端口 lsof -i :3306
列出某个用户的所有活跃的网络端口 lsof -a -u test -i

4.4 ps 进程查看器

linux上进程有5种状态:
1.运行(正在运行或在运行队列中等待)
2.中断(休眠中, 受阻, 在等待某个条件的形成或接受到信号)
3.不可中断(收到信号不唤醒和不可运行, 进程必须等待直到有中断发生)
4.僵死(进程已终止, 但进程描述符存在, 直到父进程调用wait4()系统调用后释放)
5.停止(进程收到SIGSTOP, SIGSTP, SIGTIN, SIGTOU信号后停止运行运行)

ps工具标识进程的5种状态码:
D 不可中断 uninterruptible sleep (usually IO)
R 运行 runnable (on run queue)
S 中断 sleeping
T 停止 traced or stopped
Z 僵死 a defunct (”zombie”) process

命令参数

  • a 显示所有进程
  • -a 显示同一终端下的所有程序
  • -A 显示所有进程
  • c 显示进程的真实名称
  • -N 反向选择
  • -e 等于“-A”
  • e 显示环境变量
  • f 显示程序间的关系
  • -H 显示树状结构
  • r 显示当前终端的进程
  • T 显示当前终端的所有程序
  • u 指定用户的所有进程
  • -au 显示较详细的资讯
  • -aux 显示所有包含其他使用者的行程
  • -C<命令> 列出指定命令的状况
  • –lines<行数> 每页显示的行数
  • –width<字符数> 每页显示的字符数
  • –help 显示帮助信息
  • –version 显示版本显示

输出列的含义

  • F 代表这个程序的旗标 (flag), 4 代表使用者为 super user
  • S 代表这个程序的状态 (STAT),关于各 STAT 的意义将在内文介绍
  • UID 程序被该 UID 所拥有
  • PID 进程的ID
  • PPID 则是其上级父程序的ID
  • C CPU 使用的资源百分比
  • PRI 这个是 Priority (优先执行序) 的缩写,详细后面介绍
  • NI 这个是 Nice 值,在下一小节我们会持续介绍
  • ADDR 这个是 kernel function,指出该程序在内存的那个部分。如果是个 running的程序,一般就是 “-“
  • SZ 使用掉的内存大小
  • WCHAN 目前这个程序是否正在运作当中,若为 - 表示正在运作
  • TTY 登入者的终端机位置
  • TIME 使用掉的 CPU 时间。
  • CMD 所下达的指令为何

暂时用不到好多工具的详细用法,更加详细的指南部分在需要的时候,去原文找吧,原文地址是开源的书籍

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值