top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。下面详细介绍它的使用方法。

认识top的显示结果

top命令的显示结果如下所示:

 top - 01:06:48 up  1:22,  1 user,  load average: 0.06, 0.60, 0.48
Tasks:  29 total,   1 running,  28 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.3% us,  1.0% sy,  0.0% ni, 98.7% id,  0.0% wa,  0.0% hi,  0.0% si
Mem:    191272k total,   173656k used,    17616k free,    22052k buffers
Swap:   192772k total,        0k used,   192772k free,   123988k cached

PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
1379 root      16   0  7976 2456 1980 S  0.7  1.3   0:11.03 sshd
14704 root      16   0  2128  980  796 R  0.7  0.5   0:02.72 top
1 root      16   0  1992  632  544 S  0.0  0.3   0:00.90 init
2 root      34  19     0    0    0 S  0.0  0.0   0:00.00 ksoftirqd/0
3 root      RT   0     0    0    0 S  0.0  0.0   0:00.00 watchdog/0

统计信息区

前五行是系统整体的统计信息。第一行是任务队列信息,同 uptime 命令的执行结果。其内容如下:

01:06:48 当前时间
up 1:22 系统运行时间,格式为时:分
1 user 当前登录用户数
load average: 0.06, 0.60, 0.48 系统负载,即任务队列的平均长度。
三个数值分别为 1分钟、5分钟、15分钟前到现在的平均值。

第二、三行为进程和CPU的信息。当有多个CPU时,这些内容可能会超过两行。内容如下:

Tasks: 29 total 进程总数
1 running 正在运行的进程数
28 sleeping 睡眠的进程数
0 stopped 停止的进程数
0 zombie 僵尸进程数
Cpu(s): 0.3% us 用户空间占用CPU百分比
1.0% sy 内核空间占用CPU百分比
0.0% ni 用户进程空间内改变过优先级的进程占用CPU百分比
98.7% id 空闲CPU百分比
0.0% wa 等待输入输出的CPU时间百分比
0.0% hi  
0.0% si  

最后两行为内存信息。内容如下:

Mem: 191272k total 物理内存总量
173656k used 使用的物理内存总量
17616k free 空闲内存总量
22052k buffers 用作内核缓存的内存量
Swap: 192772k total 交换区总量
0k used 使用的交换区总量
192772k free 空闲交换区总量
123988k cached 缓冲的交换区总量。
内存中的内容被换出到交换区,而后又被换入到内存,但使用过的交换区尚未被覆盖,
该数值即为这些内容已存在于内存中 的交换区的大小。
相应的内存再次被换出时可不必再对交换区写入。

进程信息区

统计信息区域的下方显示了各个进程的详细信息。首先来认识一下各列的含义。

序号 列名 含义
a PID 进程id
b PPID 父进程id
c RUSER Real user name
d UID 进程所有者的用户id
e USER 进程所有者的用户名
f GROUP 进程所有者的组名
g TTY 启动进程的终端名。不是从终端启动的进程则显示为 ?
h PR 优先级
i NI nice值。负值表示高优先级,正值表示低优先级
j P 最后使用的CPU,仅在多CPU环境下有意义
k %CPU 上次更新到现在的CPU时间占用百分比
l TIME 进程使用的CPU时间总计,单位秒
m TIME+ 进程使用的CPU时间总计,单位1/100秒
n %MEM 进程使用的物理内存 百分比
o VIRT 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
p SWAP 进程使用的虚拟内存中,被换出的大小,单位kb。
q RES 进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA
r CODE 可执行代码占用的物理 内存大小,单位kb
s DATA 可执行代码以外的部分(数据段+栈)占用的物理 内存大小,单位kb
t SHR 共享内存大小,单位kb
u nFLT 页面错误次数
v nDRT 最后一次写入到现在,被修改过的页面数。
w S 进程状态。
D =不可中断的睡眠状态
R =运行
S =睡眠
T =跟踪/停止
Z =僵尸进程
x COMMAND 命令名/命令行
y WCHAN 若该进程在睡眠,则显示睡眠中的系统函数名
z Flags 任务标志,参考 sched.h

默认情况下仅显示比较重要的 PID、USER、PR、NI、VIRT、RES、SHR、S、%CPU、%MEM、TIME+、COMMAND 列。可以通过下面的快捷键来更改显示内容。

更改显示内容

通过 f 键可以选择显示的内容。按 f 键之后会显示列的列表,按 a-z 即可显示或隐藏对应的列,最后按回车键确定。

o 键可以改变列的显示顺序。按小写的 a-z 可以将相应的列向右移动,而大写的 A-Z 可以将相应的列向左移动。最后按回车键确定。

按大写的 FO 键,然后按 a-z 可以将进程按照相应的列进行排序。而大写的 R 键可以将当前的排序倒转。

二 Grep学习笔记

作者:杨文军 日期:2006-06-13

1. grep简介
grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。Unix的grep家族包 括grep、egrep和fgrep。egrep和fgrep的命令只跟grep有很小不同。egrep是grep的扩展,支持更多的re元字符, fgrep就是fixed grep或fast grep,它们把所有的字母都看作单词,也就是说,正则表达式中的元字符表示回其自身的字面意义,不再特殊。linux使用GNU版本的grep。它功能 更强,可以通过-G、-E、-F命令行选项来使用egrep和fgrep的功能。

grep的工作方式是这样的,它在一个或多个文件中搜索字符串模板。如果模板包括空格,则必须被引用,模板后的所有字符串被看作文件名。搜索的结果被送到屏幕,不影响原文件内容。

grep可用于shell脚本,因为grep通过返回一个状态值来说明搜索的状态,如果模板搜索成功,则返回0,如果搜索不成功,则返回1,如果搜索的文件不存在,则返回2。我们利用这些返回值就可进行一些自动化的文本处理工作。

2. grep正则表达式元字符集(基本集)
^ 锚定行的开始 如:'^grep'匹配所有以grep开头的行。

$ 锚定行的结束 如:'grep$'匹配所有以grep结尾的行。

. 匹配一个非换行符的字符 如:'gr.p'匹配gr后接一个任意字符,然后是p。

* 匹配零个或多个先前字符 如:'*grep'匹配所有一个或多个空格后紧跟grep的行。 .*一起用代表任意字符。

[] 匹配一个指定范围内的字符,如'[Gg]rep'匹配Grep和grep。

[^] 匹配一个不在指定范围内的字符,如:'[^A-FH-Z]rep'匹配不包含A-R和T-Z的一个字母开头,紧跟rep的行。

/(../) 标记匹配字符,如'/(love/)',love被标记为1。

/< 锚定单词的开始,如:'/

/> 锚定单词的结束,如'grep/>'匹配包含以grep结尾的单词的行。

x/{m/} 重复字符x,m次,如:'0/{5/}'匹配包含5个o的行。

x/{m,/} 重复字符x,至少m次,如:'o/{5,/}'匹配至少有5个o的行。

x/{m,n/} 重复字符x,至少m次,不多于n次,如:'o/{5,10/}'匹配5--10个o的行。

/w 匹配文字和数字字符,也就是[A-Za-z0-9],如:'G/w*p'匹配以G后跟零个或多个文字或数字字符,然后是p。

/W /w的反置形式,匹配一个或多个非单词字符,如点号句号等。

/b 单词锁定符,如: '/bgrepb/'只匹配grep。

3. 用于egrep和 grep -E的元字符扩展集+
匹配一个或多个先前的字符。如:'[a-z]+able',匹配一个或多个小写字母后跟able的串,如loveable,enable,disable等。

? 匹配零个或多个先前的字符。如:'gr?p'匹配gr后跟一个或没有字符,然后是p的行。

a|b|c 匹配a或b或c。如:grep|sed匹配grep或sed

() 分组符号,如:love(able|rs)ov+匹配loveable或lovers,匹配一个或多个ov。

x{m},x{m,},x{m,n} 作用同x/{m/},x/{m,/},x/{m,n/}

4. POSIX字符类
为 了在不同国家的字符编码中保持一至,POSIX(The Portable Operating System Interface)增加了特殊的字符类,如[:alnum:]是A-Za-z0-9的另一个写法。要把它们放到[]号内才能成为正则表达式,如[A- Za-z0-9]或[[:alnum:]]。在linux下的grep除fgrep外,都支持POSIX的字符类。

[:alnum:] 文字数字字符

[:alpha:] 文字字符

[:digit:] 数字字符

[:graph:] 非空字符(非空格、控制字符)

[:lower:] 小写字符

[:cntrl:] 控制字符

[:print:] 非空字符(包括空格)

[:punct:] 标点符号

[:space:] 所有空白字符(新行,空格,制表符)

[:upper:] 大写字符

[:xdigit:] 十六进制数字(0-9,a-f,A-F)

5. Grep命令选项
-? 同时显示匹配行上下的?行,如:grep -2 pattern filename同时显示匹配行的上下2行。

-b,--byte-offset 打印匹配行前面打印该行所在的块号码。

-c,--count 只打印匹配的行数,不显示匹配的内容。

-f File,--file=File 从文件中提取模板。空文件中包含0个模板,所以什么都不匹配。

-h,--no-filename 当搜索多个文件时,不显示匹配文件名前缀。

-i,--ignore-case 忽略大小写差别。

-q,--quiet 取消显示,只返回退出状态。0则表示找到了匹配的行。

-l,--files-with-matches 打印匹配模板的文件清单。

-L,--files-without-match 打印不匹配模板的文件清单。

-n,--line-number 在匹配的行前面打印行号。

-s,--silent 不显示关于不存在或者无法读取文件的错误信息。

-v,--revert-match 反检索,只显示不匹配的行。

-w,--word-regexp 如果被/<和/>引用,就把表达式做为一个单词搜索。

-V,--version 显示软件版本信息。

6. 实例
要用好grep这个工具,其实就是要写好正则表达式,所以这里不对grep的所有功能进行实例讲解,只列几个例子,讲解一个正则表达式的写法。

$ ls -l | grep '^a'
通过管道过滤ls -l输出的内容,只显示以a开头的行。

$ grep 'test' d*
显示所有以d开头的文件中包含test的行。

$ grep 'test' aa bb cc
显示在aa,bb,cc文件中匹配test的行。

$ grep '[a-z]/{5/}' aa
显示所有包含每个字符串至少有5个连续小写字符的字符串的行。

$ grep 'w/(es/)t.*/1' aa
如果west被匹配,则es就被存储到内存中,并标记为1,然后搜索任意个字符(.*),这些字符后面紧跟着另外一个es(/1),找到就显示该行。如果用egrep或grep -E,就不用"/"号进行转义,直接写成'w(es)t.*/1'就可以了。

# grep '^n' datafile  打印所有以n开头的行.

# grep '4$' datafile  打印所有以4结束的行.

# grep '5/..' datafile  打印包含第一个字符是5,紧跟着一个点,再后面是任意一个字符串的行.除非在点的前面有一个反斜杠,否则它就表示一个任意字符.

# grep '/.5' datafile  打印所有包含字符串".5"的行.

# grep '^[wesn]' datafile  打印所有以w,e,s,n开头的行.

# grep '[A-Z][A-Z] [A-Z]' datafile  打印所有包含前两个字符是大写字母,后面跟一个空格及一个大写字母的字符串的行.

# grep 'ss* ' datafile  打印所有包含一个或者多个s且后面跟有一个空格的字符串的行.

# grep '[a-z]/{9/}' datafile  打印所有包含每个字符串至少有9个连续小写字母的字符串行.

# grep '/<[a-z].*n/>' datafile  打印所有第一个字母是小写字母,紧跟着是任意个字符,最后以n结束的字符串行.

三 FTP命令行使用精萃

作者:杨文军 日期:2006-04-05

FTP命令是Internet用户使用最频繁的命令之一,不论是在DOS还是UNIX操作系统下使用 FTP,都会遇到大量的FTP内部命令。熟悉并灵活应用FTP的内部命令,可以大大方便使用者,并收到事半功倍之效。

  FTP的命令行格式为: ftp -v -d -i -n -g [主机名] ,其中

  -v 显示远程服务器的所有响应信息;
  -d 使用调试方式;
  -i 限制ftp的自动登录,即不使用;
  -n etrc文件;
  -g 取消全局文件名。

  ftp使用的内部命令如下(中括号表示可选项):
  1. ![cmd[args]]:在本地机中执行交互shell,exit回到ftp环境,如:!ls*.zip。

  2. $ macro-ame[args]:执行宏定义macro-name。

  3. account[password]:提供登录远程系统成功后访问系统资源所需的补充口令。

  4.append local-file[remote-file]:将本地文件追加到远程系统主机,若未指定远程系统文件名,则使用本地文件名。

  5. ascii:使用ascii类型传输方式。

  6. bell:每个命令执行完毕后计算机响铃一次。

  7. bin:使用二进制文件传输方式。

  8. bye:退出ftp会话过程。

  9. case:在使用mget时,将远程主机文件名中的大写转为小写字母。

  10. cd remote-dir:进入远程主机目录。

  11. cdup:进入远程主机目录的父目录。

  12. chmod mode file-name:将远程主机文件file-name的存取方式设置为mode,如: chmod 777 a.out 。

  13. close:中断与远程服务器的ftp会话(与open对应)。

  14. cr:使用asscii方式传输文件时,将回车换行转换为回行。

  15. delete remote-file:删除远程主机文件。

  16. debug[debug-value]:设置调试方式, 显示发送至远程主机的每条命令,如: deb up 3,若设为0,表示取消debug。

  17.dir[remote-dir][local-file]:显示远程主机目录,并将结果存入本地文件local-file。

  18. disconnection:同close。

  19. form format:将文件传输方式设置为format,缺省为file方式。

  20. get remote-file[local-file]: 将远程主机的文件remote-file传至本地硬盘的local-file。

  21. glob:设置mdelete,mget,mput的文件名扩展,缺省时不扩展文件名,同命令行的-g参数。

  22. hash:每传输1024字节,显示一个hash符号(#)。

  23. help[cmd]:显示ftp内部命令cmd的帮助信息,如:help get。

  24. idle[seconds]:将远程服务器的休眠计时器设为[seconds]秒。

  25. image:设置二进制传输方式(同binary)。

  26. lcd[dir]:将本地工作目录切换至dir。

  27. ls[remote-dir][local-file]:显示远程目录remote-dir, 并存入本地文件local-file。

  28. macdef macro-name:定义一个宏,遇到macdef下的空行时,宏定义结束。

  29. mdelete[remote-file]:删除远程主机文件。

  30. mdir remote-files local-file:与dir类似,但可指定多个远程文件,如: mdir *.o.*.zipoutfile 。

  31. mget remote-files:传输多个远程文件。

  32. mkdir dir-name:在远程主机中建一目录。

  33. mls remote-file local-file:同nlist,但可指定多个文件名。

  34. mode[modename]:将文件传输方式设置为modename, 缺省为stream方式。

  35. modtime file-name:显示远程主机文件的最后修改时间。

  36. mput local-file:将多个文件传输至远程主机。

  37. newer file-name: 如果远程机中file-name的修改时间比本地硬盘同名文件的时间更近,则重传该文件。

  38. nlist[remote-dir][local-file]:显示远程主机目录的文件清单,并存入本地硬盘的local-file。

   39. nmap[inpattern outpattern]:设置文件名映射机制, 使得文件传输时,文件中的某些字符相互转换,如:nmap $1.$2.$3[$1,$2].[$2,$3],则传输文件a1.a2.a3时,文件名变为a1,a2。该命令特别适用于远程主机为非UNIX机的情 况。

  40. ntrans[inchars[outchars]]:设置文件名字符的翻译机制,如ntrans1R,则文件名LLL将变为RRR。

  41. open host[port]:建立指定ftp服务器连接,可指定连接端口。

  42. passive:进入被动传输方式。

  43. prompt:设置多个文件传输时的交互提示。

  44. proxy ftp-cmd:在次要控制连接中,执行一条ftp命令,该命令允许连接两个ftp服务器,以在两个服务器间传输文件。第一条ftp命令必须为open,以首先建立两个服务器间的连接。

  45. put local-file[remote-file]:将本地文件local-file传送至远程主机。

  46. pwd:显示远程主机的当前工作目录。

  47. quit:同bye,退出ftp会话。

  48. quote arg1,arg2...:将参数逐字发至远程ftp服务器,如:quote syst。

  49. recv remote-file[local-file]:同get。

  50. reget remote-file[local-file]:类似于get,但若local-file存在,则从上次传输中断处续传。

  51. rhelp[cmd-name]:请求获得远程主机的帮助。

  52. rstatus[file-name]:若未指定文件名,则显示远程主机的状态,否则显示文件状态。

  53. rename[from][to]:更改远程主机文件名。

  54. reset:清除回答队列。

  55. restart marker:从指定的标志marker处,重新开始get或put,如:restart 130。

  56. rmdir dir-name:删除远程主机目录。

  57. runique:设置文件名唯一性存储。

  58. send local-file[remote-file]:同put。

  59. sendport:设置PORT命令的使用。

  60. site arg1,arg2...:将参数作为SITE命令逐字发送至远程ftp主机。

  61. size file-name:显示远程主机文件大小,如:site idle 7200。

  62. status:显示当前ftp状态。

  63. struct[struct-name]:将文件传输结构设置为struct-name,缺省时使用stream结构。

  64. sunique:将远程主机文件名存储设置为唯一(与runique对应)。

  65. system:显示远程主机的操作系统类型。

  66. tenex:将文件传输类型设置为TENEX机的所需的类型。

  67. tick:设置传输时的字节计数器。

  68. trace:设置包跟踪。

  69. type[type-name]:设置文件传输类型为type-name,缺省为ascii,如:type binary,设置二进制传输方式。

  70. umask[newmask]:将远程服务器的缺省umask设置为newmask,如:umask 3。
  71. user user-name[password][account]:向远程主机表明自己的身份,需要口令时,必须输入口令,如:user anonymous my@email。

  72. verbose:同命令行的-v参数,即设置详尽报告方式,ftp服务器的所有响应都将显示给用户,缺省为on。

  73. ?[cmd]:同help。

AID编者附注:如果服务器支持,可以使用quote "site pswd oldpassword newpassword"来修改密码

四 Linux的常用网络命令

作者:杨文军 日期:2006-04-05

计算机网络的主要优点是能够实现资源和信息的共享,并且用户可以远程访问信息。Linux提供了一组强有力的网络命令来为用户服务,这些工具能够帮助用户登录到远程计算机上、传输文件和执行远程命令等。 本章介绍下列几个常用的有关网络操作的命令:

ftp 传输文件
telnet 登录到远程计算机上
r - 使用各种远程命令
netstat 查看网络的状况
nslookup 查询域名和IP地址的对应
finger 查询某个使用者的信息
ping 查询某个机器是否在工作

使用ftp命令进行远程文件传输
ftp 命令是标准的文件传输协议的用户接口。ftp是在TCP/IP网络上的计算机之间传输文件的简单有效的方法。它允许用户传输ASCII文件和二进制文件。 在ftp会话过程中,用户可以通过使用ftp客户程序连接到另一台计算机上。从此,用户可以在目录中上下移动、列出目录内容、把文件从远程机拷贝到本地机 上、把文件从本地机传输到远程系统中。

需要注意的是,如果用户没有那个文件的存取权限,就不能从远程系统中获得文件或向远程系统传输文 件。 为了使用ftp来传输文件,用户必须知道远程计算机上的合法用户名和口令。这个用户名/口令的组合用来确认ftp 会话,并用来确定用户对要传输的文件可以进行什么样的访问。另外,用户显然需要知道对其进行ftp 会话的计算机的名字或IP地址。

Ftp命令的功能是在本地机和远程机之间传送文件。该命令的一般格式如下:
$ ftp 主机名/IP

其 中“主机名/IP”是所要连接的远程机的主机名或IP地址。在命令行中,主机名属于选项,如果指定主机名,ftp将试图与远程机的ftp服务程序进行连 接;如果没有指定主机名,ftp将给出提示符,等待用户输入命令: $ ftp ftp > 此时在ftp>提示符后面输入open命令加主机名或IP地址,将试图连接指定的主机。 不管使用哪一种方法,如果连接成功,需要在远程机上登录。用户如果在远程机上有帐号,就可以通过ftp使用这一帐号并需要提供口令。
在远程机上的 用户帐号的读写权限决定该用户在远程机上能下载什么文件和将上载文件放到哪个目录中。 如果没有远程机的专用登录帐号,许多ftp站点设有可以使用的特殊帐号。这个帐号的登录名为anonymous(也称为匿名ftp),当使用这一帐号时, 要求输入email地址作为口令。 如果远程系统提供匿名ftp服务,用户使用这项服务可以登录到特殊的,供公开使用的目录。

一般专门提 供两个目录:pub目录和incoming目录。pub目录包含该站点供公众使用的所有文件,incoming目录存放上载到该站点的文件。 一旦用户使用ftp在远程站点上登录成功,将得到“ftp>”提示符。现在可以自由使用ftp提供的命令,可以用 help命令取得可供使用的命令清单,也可以在 help命令后面指定具体的命令名称,获得这条命令的说明。
最常用的命令有:
ls 列出远程机的当前目录
cd 在远程机上改变工作目录
lcd 在本地机上改变工作目录
ascii 设置文件传输方式为ASCII模式
binary 设置文件传输方式为二进制模式
close终止当前的ftp会话
hash 每次传输完数据缓冲区中的数据后就显示一个#号
get(mget) 从远程机传送指定文件到本地机
put(mput) 从本地机传送指定文件到远程机
open 连接远程ftp站点
quit断开与远程机的连接并退出ftp
? 显示本地帮助信息
! 转到Shell中

下面简单将ftp常用命令作一简介。
启 动ftp会话 open命令用于打开一个与远程主机的会话。该命令的一般格式是: open 主机名/IP 如果在ftp 会话期间要与一个以上的站点连接,通常只用不带参数的ftp命令。如果在会话期间只想与一台计算机连接,那么在命令行上指定远程主机名或IP地址作为 ftp命令的参数。 终止ftp会话 close、disconnect、quit和bye命令用于终止与远程机的会话。close和disronnect命令关闭与远程机的连接,但是使用户 留在本地计算机的ftp程序中。quit和bye命令都关闭用户与远程机的连接,然后退出用户机上的ftp 程序。 改变目录 “cd [目录]”命令用于在ftp会话期间改变远程机上的目录,lcd命令改变本地目录,使用户能指定查找或放置本地文件的位置。 远程目录列表 ls命令列出远程目录的内容,就像使用一个交互shell中的ls命令一样。ls命令的一般格式是: ls [目录] [本地文件] 如果指定了目录作为参数,那么ls就列出该目录的内容。如果给出一个本地文件的名字,那么这个目录列表被放入本地机上您指定的这个文件中。 从远程系统获取文件 get和mget命令用于从远程机上获取文件。get命令的一般格式为: get 文件名 您还可以给出本地文件名,这个文件名是这个要获取的文件在您的本地机上创建时的文件名。如果您不给出一个本地文件名,那么就使用远程文件原来的名字。 mget命令一次获取多个远程文件。mget命令的一般格式为: mget 文件名列表 使用用空格分隔的或带通配符的文件名列表来指定要获取的文件,对其中的每个文件都要求用户确认是否传送。   向远程系统发送文件 put和mput命令用于向远程机发送文件。Put命令的一般格式为: put 文件名 mput命令一次发送多个本地文件,mput命令的一般格式为: mput 文件名列表 使用用空格分隔的或带通配符的文件名列表来指定要发送的文件。对其中的每个文件都要求用户确认是否发送。 改变文件传输模式 默认情况下,ftp按ASCII模式传输文件,用户也可以指定其他模式。ascii和brinary命令的功能是设置传输的模式。用ASCII模式传输文 件对纯文本是非常好的,但为避免对二进制文件的破坏,用户可以以二进制模式传输文件。 检查传输状态 传输大型文件时,可能会发现让ftp提供关于传输情况的反馈信息是非常有用的。hash命令使ftp在每次传输完数据缓冲区中的数据后,就在屏幕上打印一 个#字符。本命令在发送和接收文件时都可以使用。 ftp中的本地命令 当您使用ftp时,字符“!”用于向本地机上的命令shell传送一个命令。如果用户处在ftp会话中,需要shell做某些事,就很有用。例如用户要建 立一个目录来保存接收到的文件。如果输入!mkdir new_dir,那么Linux就在用户当前的本地目录中创建一个名为new_dir 的目录。

从远程机grunthos下载二进制数据文件的典型对话过程如下:
$ ftp grunthos Connected to grunthos 220 grunthos ftp server Name (grunthos:pc): anonymous 33l Guest login ok, send your complete e-mail address as password. Password: 230 Guest 1ogin ok, access restrictions apply. Remote system type is UNIX. ftp > cd pub 250 CWD command successful. ftp > ls 200 PORT command successful. l50 opening ASCII mode data connection for /bin/1s. total ll4 rog1 rog2 226 Transfer comp1ete . ftp > binary 200 type set to I. ftp > hash Hash mark printing on (1024 bytes/hash mark). ftp > get rog1 200 PORT command successfu1. 150 opening BINARY mode data connection for rogl (l4684 bytes). # # # # # # # # # # # # # 226 Transfer complete. 14684 bytes received in 0.0473 secs (3e + 02 Kbytes/sec) ftp > quit 22l Goodbye.

使用telnet命令访问远程计算机
用 户使用telnet命令进行远程登录。该命令允许用户使用telnet协议在远程计算机之间进行通信,用户可以通过网络在远程计算机上登录,就像登录到本 地机上执行命令一样。 为了通过telnet登录到远程计算机上,必须知道远程机上的合法用户名和口令。虽然有些系统确实为远程用户提供登录功能,但出于对安全的考虑,要限制来 宾的操作权限,因此,这种情况下能使用的功能是很少的。当允许远程用户登录时,系统通常把这些用户放在一个受限制的shell中,以防系统被怀有恶意的或 不小心的用户破坏。 用户还可以使用telnet从远程站点登录到自己的计算机上,检查电子邮件、编辑文件和运行程序,就像在本地登录一样。
但 是,用户只能使用基于终端的环境而不是X Wndows环境,telnet只为普通终端提供终端仿真,而不支持 X Wndow等图形环境。 telnet命令的一般形式为: telnet 主机名/IP 其中“主机名/IP”是要连接的远程机的主机名或IP地址。如果这一命令执行成功,将从远程机上得到login:提示符。 使用telnet命令登录的过程如下: $ telnet 主机名/IP 启动telnet会话。 一旦telnet成功地连接到远程系统上,就显示登录信息并提示用户输人用户名和口令。如果用户名和口令输入正确,就能成功登录并在远程系统上工作。 在telnet提示符后面可以输入很多命令,用来控制telnet会话过程,在telnet联机帮助手册中对这些命令有详细的说明。

下面是一台Linux计算机上的telnet会话举例:
$ telnet server. somewhere. com Trying 127.0.0.1… Connected to serve. somewhere. com. Escape character is /'?]/'. “TurboLinux release 4. 0 (Colgate)   kernel 2.0.18 on an I486   login: bubba password: Last login:Mon Nov l5 20:50:43 for localhost Linux 2. 0.6. (Posix). server: ~$ server: ~$ logout Connection closed by foreign host $

用户结束了远程会 话后,一定要确保使用logout命令退出远程系统。然后telnet报告远程会话被关闭,并返回到用户的本地机的Shell提示符下。 r-系列命令 除ftp和telnet以外,还可以使用r-系列命令访问远程计算机和在网络上交换文件。 使用r-系列命令需要特别注意,因为如果用户不小心,就会造成严重的安全漏洞。用户发出一个r-系列命令后,远程系统检查名为/etc /hosts.equiv的文件,以查看用户的主机是否列在这个文件中。如果它没有找到用户的主机,就检查远程机上同名用户的主目录中名为.rhosts 的文件,看是否包括该用户的主机。如果该用户的主机包括在这两个文件中的任何一个之中,该用户执行r-系列命令就不用提供口令。

虽然用户每次访问远程机时不用键入口令可能是非常方便的,但是它也可能会带来严重的安全问题。我们建议用户在建立/etc/hosts.equiv和.rhosts文件之前,仔细考虑r-命令隐含的安全问题。

rlogin命令
rlogin 是“remote login”(远程登录)的缩写。该命令与telnet命令很相似,允许用户启动远程系统上的交互命令会话。rlogin 的一般格式是:
rlogin [ -8EKLdx ] [ -e char ] [-k realm ] [ - l username ] host

一般最常用的格式是: rlogin host 该命令中各选项的含义为:
-8 此选项始终允许8位输入数据通道。该选项允许发送格式化的ANSI字符和其他的特殊代码。如果不用这个选项,除非远端的终止和启动字符不是或,否则就去掉奇偶校验位。
-E 停止把任何字符当作转义字符。当和-8选项一起使用时,它提供一个完全的透明连接。
-K 关闭所有的Kerberos确认。只有与使用Kerberos 确认协议的主机连接时才使用这个选项。
-L 允许rlogin会话在litout模式中运行。要了解更多信息,请查阅tty联机帮助。
-d 打开与远程主机进行通信的TCP sockets的socket调试。要了解更多信息,请查阅setsockopt的联机帮助。
-e 为rlogin会话设置转义字符,默认的转义字符是“~”,用户可以指定一个文字字符或一个//nnn形式的八进制数。
-k 请求rlogin获得在指定区域内的远程主机的Kerberos许可,而不是获得由krb_realmofhost(3)确定的远程主机区域内的远程主机的Kerberos 许可。
-x 为所有通过rlogin会话传送的数据打开DES加密。这会影响响应时间和CPU利用率,但是可以提高安全性。

rsh命令
rsh是“remote shell”(远程 shell)的缩写。 该命令在指定的远程主机上启动一个shell并执行用户在rsh命令行中指定的命令。如果用户没有给出要执行的命令,rsh就用rlogin命令使用户登录到远程机上。
rsh命令的一般格式是:
rsh [-Kdnx] [-k realm] [-l username] host [command]
一般常用的格式是:
rsh host [command ]
command可以是从shell提示符下键人的任何Linux命令。
rsh命令中各选项的含义如下:
-K 关闭所有的Kerbero确认。该选项只在与使用Kerbero确认的主机连接时才使用。
-d 打开与远程主机进行通信的TCP sockets的socket调试。要了解更多的信息,请查阅setsockopt的联机帮助。
-k 请求rsh获得在指定区域内的远程主机的Kerberos许可,而不是获得由krb_relmofhost(3)确定的远程主机区域内的远程主机的Kerberos许可。
-l 缺省情况下,远程用户名与本地用户名相同。本选项允许指定远程用户名,如果指定了远程用户名,则使用Kerberos 确认,与在rlogin命令中一样。
-n 重定向来自特殊设备/dev/null的输入。
-x 为传送的所有数据打开DES加密。这会影响响应时间和CPU利用率,但是可以提高安全性。   Linux把标准输入放入rsh命令中,并把它拷贝到要远程执行的命令的标准输入中。它把远程命令的标准输出拷贝到rsh的标准输出中。它还把远程标准错 误拷贝到本地标准错误文件中。任何退出、中止和中断信号都被送到远程命令中。当远程命令终止了,rsh也就终止了。

rcp命令
rcp代表“remote file copy”(远程文件拷贝)。该命令用于在计算机之间拷贝文件。
rcp命令有两种格式。第一种格式用于文件到文件的拷贝;第二种格式用于把文件或目录拷贝到另一个目录中。
rcp命令的一般格式是:
rcp [-px] [-k realm] file1 file2 rcp [-px] [-r] [-k realm] file
directory 每个文件或目录参数既可以是远程文件名也可以是本地文件名。远程文件名具有如下形式:rname@rhost:path,其中rname是远程用户名,rhost是远程计算机名,path是这个文件的路径。
rcp命令的各选项含义如下:
-r 递归地把源目录中的所有内容拷贝到目的目录中。要使用这个选项,目的必须是一个目录。
-p 试图保留源文件的修改时间和模式,忽略umask。
-k 请求rcp获得在指定区域内的远程主机的Kerberos 许可,而不是获得由krb_relmofhost(3)确定的远程主机区域内的远程主机的Kerberos许可。
-x 为传送的所有数据打开DES加密。这会影响响应时间和CPU利用率,但是可以提高安全性。 如果在文件名中指定的路径不是完整的路径名,那么这个路径被解释为相对远程机上同名用户的主目录。如果没有给出远程用户名,就使用当前用户名。如果远程机 上的路径包含特殊shell字符,需要用反斜线(//)、双引号(”)或单引号(’)括起来,使所有的shell元字符都能被远程地解释。 需要说明的是,rcp不提示输入口令,它通过rsh命令来执行拷贝。 - Turbolinux 提供稿件

五 使用truss、strace或ltrace诊断软件的"疑难杂症"

 

李凯斌 , 项目经理
本文通过三个实际案例演示如何使用truss、strace和ltrace这三个常用的调试工具来快速诊断软件的"疑难杂症"。

简介

进程无法启动,软件运行速度突然变慢,程序的"Segment Fault"等等都是让ÿ个Unix系统用户头痛的问题,本文通过三个实际案例演示如何使用truss、strace和ltrace这三个常用的调试工具来快速诊断软件的"疑难杂症"。

truss和strace用来 跟踪一个进程的系统调用或信号产生的情况 ,而 ltrace用来 跟踪进程调用库函数的情况 。truss 是早期为System V R4开发的调试程序,包括Aix、FreeBSD在内的大部分Unix系统都自带了这个工具;而strace最初是为SunOS系统编写的,ltrace 最早出现在GNU/Debian Linux中。这两个工具现在也已被移植到了大部分Unix系统中,大多数Linux发行版都自带了strace和ltrace,而FreeBSD也可通 过Ports安装它们。

你不仅可以从命令行调试一个新开始的程序,也可以把truss、strace或ltrace绑定到一个已有的PID上来调试一个正在运行的程序。三个调试工具的基本使用方法大体相同,下面仅介绍三者共有,而且是最常用的三个命令行参数:


-f :除了跟踪当前进程外,还跟踪其子进程。
-o file :将输出信息写到文件file中,而不是显示到标准错误输出(stderr)。
-p pid :绑定到一个由pid对应的正在运行的进程。此参数常用来调试后台进程。

使用上述三个参数基本上就可以完成大多数调试任务了,下面举几个命令行例子:


truss -o ls.truss ls -al: 跟踪ls -al的运行,将输出信息写到文件/tmp/ls.truss中。
strace -f -o vim.strace vim: 跟踪vim及其子进程的运行,将输出信息写到文件vim.strace。
ltrace -p 234: 跟踪一个pid为234的已经在运行的进程。

三个调试工具的输出结果格式也很相似,以strace为例:


brk(0)                                  = 0x8062aa8
brk(0x8063000)                          = 0x8063000
mmap2(NULL, 4096, PROT_READ, MAP_PRIVATE, 3, 0x92f) = 0x40016000

ÿ一行都是一条系统调用,等号左边是系统调用的函数名及其参数,右边是该调用的返回值。 truss、strace和ltrace的工作原理大同小异,都是使用ptrace系统调用跟踪调试运行中的进程,详细原理不在本文讨论范Χ内,有兴趣可以参考它们的源代码。

下面举两个实例演示如何利用这三个调试工具诊断软件的"疑难杂症":


案例一:运行clint出现Segment Fault错误

操作系统:FreeBSD-5.2.1-release

clint是一个C++静态源代码分析工具,通过Ports安装好之后,运行:


# clint foo.cpp
Segmentation fault (core dumped)

在Unix系统中遇见"Segmentation Fault"就像在MS Windows中弹出"非法操作"对话框一样令人讨厌。OK,我们用truss给clint"把把脉":


# truss -f -o clint.truss clint
Segmentation fault (core dumped)
# tail clint.truss
739: read(0x6,0x806f000,0x1000)               = 4096 (0x1000)
739: fstat(6,0xbfbfe4d0)                       = 0 (0x0)
739: fcntl(0x6,0x3,0x0)                        = 4 (0x4)
739: fcntl(0x6,0x4,0x0)                        = 0 (0x0)
739: close(6)                                    = 0 (0x0)
739: stat("/root/.clint/plugins",0xbfbfe680)   ERR#2 'No such file or directory'
SIGNAL 11
SIGNAL 11
Process stopped because of:  16
process exit, rval = 139

我们用truss跟踪clint的系统调用执行情况,并把结果输出到文件clint.truss,然后用tail查看最后几行。注意看clint执行的最后一条系统调用(倒数第五行): stat("/root/.clint/plugins",0xbfbfe680) ERR#2 'No such file or directory' ,问题就出在这里:clint找不到目¼"/root/.clint/plugins",从而引发了段错误。怎样解决?很简单: mkdir -p /root/.clint/plugins ,不过这次运行clint还是会"Segmentation Fault"9。继续用truss跟踪,发现clint还需要这个目¼"/root/.clint/plugins/python",建好这个目¼后clint终于能够正常运行了。


案例二:vim启动速度明显变慢

操作系统:FreeBSD-5.2.1-release

vim版本为6.2.154,从命令行运行vim后,要等待近半分钟才能进入编辑界面,而且û有任何错误输出。仔细检查 了.vimrc和所有的 vim脚本都û有错误配置,在网上也找不到类似问题的解决办法,难不成要hacking source code?û有必要,用truss就能找到问题所在:


# truss -f -D -o vim.truss vim

这里-D参数的作用是:在ÿ行输出前加上相对时间戳,即ÿ执行一条系统调用所耗费的时间。我们只要关注哪些系统调用耗费的时间比较长就可以了,用less仔细查看输出文件vim.truss,很快就找到了疑点:


735: 0.000021511 socket(0x2,0x1,0x0)       = 4 (0x4)
735: 0.000014248 setsockopt(0x4,0x6,0x1,0xbfbfe3c8,0x4) = 0 (0x0)
735: 0.000013688 setsockopt(0x4,0xffff,0x8,0xbfbfe2ec,0x4) = 0 (0x0)
735: 0.000203657 connect(0x4,{ AF_INET 10.57.18.27:6000 },16) ERR#61 'Connection refused'
735: 0.000017042 close(4)          = 0 (0x0)
735: 1.009366553 nanosleep(0xbfbfe468,0xbfbfe460) = 0 (0x0)
735: 0.000019556 socket(0x2,0x1,0x0)       = 4 (0x4)
735: 0.000013409 setsockopt(0x4,0x6,0x1,0xbfbfe3c8,0x4) = 0 (0x0)
735: 0.000013130 setsockopt(0x4,0xffff,0x8,0xbfbfe2ec,0x4) = 0 (0x0)
735: 0.000272102 connect(0x4,{ AF_INET 10.57.18.27:6000 },16) ERR#61 'Connection refused'
735: 0.000015924 close(4)          = 0 (0x0)
735: 1.009338338 nanosleep(0xbfbfe468,0xbfbfe460) = 0 (0x0)

vim试图连接10.57.18.27这台主机的6000端口(第四行的connect()),连接失败后,睡眠一秒钟继 续重试(第6行的 nanosleep())。以上片断循环出现了十几次,ÿ次都要耗费一秒多钟的时间,这就是vim明显变慢的原因。可是,你肯定会纳闷:"vim怎ô会无 缘无故连接其它计算机的6000端口呢?"。问得好,那ô请你回想一下6000是什ô服务的端口?û错,就是X Server。看来vim是要把输出定向到一个远程X Server,那ôShell中肯定定义了DISPLAY变量,查看.cshrc,果然有这ô一行: setenv DISPLAY ${REMOTEHOST}:0 ,把它注释掉,再重新登¼,问题就解决了。


案例三:用调试工具掌握软件的工作原理

操作系统:Red Hat Linux 9.0

用调试工具实时跟踪软件的运行情况不仅是诊断软件"疑难杂症"的有效的手段,也可帮助我们理清软件的"脉络",即快速掌握 软件的运行流程和工作原 理,不失为一种学习源代码的辅助方法。下面这个案例展现了如何使用strace通过跟踪别的软件来"触发灵感",从而解决软件开发中的难题的。

大家都知道,在进程内打开一个文件,都有Ψ一一个文件描述符(fd:file descriptor)与这个文件对应。而本人在开发一个软件过程中遇到这样一个问题:已知一个fd ,如何获取这个fd所对应文件的完整·径?不管是Linux、FreeBSD或是其它Unix系统都û有提供这样的API,怎ô办呢?我们换个角度思考: Unix下有û有什ô软件可以获取进程打开了哪些文件?如果你经验足够丰富,很容易想到lsof,使用它既可以知道进程打开了哪些文件,也可以了解一个文 件被哪个进程打开。

好,我们用一个小程序来试验一下lsof,看它是如何获取进程打开了哪些文件。


/* testlsof.c */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(void)
{
open("/tmp/foo", O_CREAT|O_RDONLY);    /* 打开文件/tmp/foo */
sleep(1200);                                /* 睡眠1200秒,以便进行后续操作 */
return 0;
}

将testlsof放入后台运行,其pid为3125。命令lsof -p 3125查看进程3125打开了哪些文件,我们用strace跟踪lsof的运行,输出结果保存在lsof.strace中:


# gcc testlsof.c -o testlsof
# ./testlsof &
[1] 3125
# strace -o lsof.strace lsof -p 3125

我们以"/tmp/foo"为关键字搜索输出文件lsof.strace,结果只有一条:


# grep '/tmp/foo' lsof.strace
readlink("/proc/3125/fd/3", "/tmp/foo", 4096) = 8

原来lsof巧妙的利用了/proc/nnnn/fd/目¼(nnnn为pid):Linux内核会为ÿ一个进程在 /proc/建立一个以其pid 为名的目¼用来保存进程的相关信息,而其子目¼fd保存的是该进程打开的所有文件的fd。目标离我们很近了。好,我们到/proc/3125/fd/看个 究竟:


# cd /proc/3125/fd/
# ls -l
total 0
lrwx------    1 root     root           64 Nov  5 09:50 0 -> /dev/pts/0
lrwx------    1 root     root           64 Nov  5 09:50 1 -> /dev/pts/0
lrwx------    1 root     root           64 Nov  5 09:50 2 -> /dev/pts/0
lr-x------    1 root     root           64 Nov  5 09:50 3 -> /tmp/foo
# readlink /proc/3125/fd/3
/tmp/foo

答案已经很明显了:/proc/nnnn/fd/目¼下的ÿ一个fd文件都是符号链接,而此链接就指向被该进程打开的一个文件。我们只要用readlink()系统调用就可以获取某个fd对应的文件了,代码如下:


#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
int get_pathname_from_fd(int fd, char pathname[], int n)
{
char buf[1024];
pid_t  pid;
bzero(buf, 1024);
pid = getpid();
snprintf(buf, 1024, "/proc/%i/fd/%i", pid, fd);
return readlink(buf, pathname, n);
}
int main(void)
{
int fd;
char pathname[4096];
bzero(pathname, 4096);
fd = open("/tmp/foo", O_CREAT|O_RDONLY);
get_pathname_from_fd(fd, pathname, 4096);
printf("fd=%d; pathname=%s/n", fd, pathname);
return 0;
}

【注】出于安全方面的考虑,在FreeBSD 5 之后系统默认已经不再自动装载proc文件系统,因此,要想使用truss或strace跟踪程序,你必须手工装载proc文件系统:mount -t procfs proc /proc;或者在/etc/fstab中加上一行:


proc                   /proc           procfs  rw              0       0

ltrace不需要使用procfs。

六 linux 调试工具 —— Valgrind 使用初探

 
 

Valgrind 是在linux系统下开发应用程序时用于调试内存问题的工具。它尤其擅长发现内存管理的问题,它可以检查程序运行时的内存泄漏问题。

它的官方网址是 http://www.valgrind.org/

下载最新版本的Valgrind,目前是3.2.0。 wget http://www.valgrind.org/downloads/valkyrie-1.2.0.tar.bz2

执行常规的安装步骤:./confgure && make && make install。注意: 系统必须安装QT的开发包。即便这样在make 时还是出现qplatformdefs.h这个文件找不到的情况,导致make失败。查找系统中的qplatformdefs.h 之后,发现没有存在于qt的标准头文件目录/usr/lib/qt-3.3/include。如是将/usr/lib/qt-3.3/mkspecs /linux-g++/ 目录下该头文件复制标准头文件目录,重新make ,后面一切OK。

初次使用

    编译如下代码:  gcc -Wall example.c -g -o example 

#include <stdlib.h>

void f(void)
{
int* x = malloc(10 * sizeof(int));
x[10] = 0;        // problem 1: heap block overrun
}                    // problem 2: memory leak -- x not freed

int main(void)
{
f();
return 0;
}

注意:gcc 的-g 选项让Valgrind调试输出时指出相应信息的代码所在的行号。

valgrind --tool=memcheck --leak-check=yes ./example
==6742== Memcheck, a memory error detector for x86-linux.
==6742== Copyright (C) 2002-2004, and GNU GPL'd, by Julian Seward et al.
==6742== Using valgrind-2.2.0, a program supervision framework for x86-linux.
==6742== Copyright (C) 2000-2004, and GNU GPL'd, by Julian Seward et al.
==6742== For more details, rerun with: -v
==6742==
==6742== Invalid write of size 4
==6742==    at 0x8048384: f (example.c:6)
==6742==    by 0x80483AC: main (example.c:12)
==6742==  Address 0x1B908050 is 0 bytes after a block of size 40 alloc'd
==6742==    at 0x1B904984: malloc (vg_replace_malloc.c:131)
==6742==    by 0x8048377: f (example.c:5)
==6742==    by 0x80483AC: main (example.c:12)
==6742==
==6742== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 12 from 1)
==6742== malloc/free: in use at exit: 40 bytes in 1 blocks.
==6742== malloc/free: 1 allocs, 0 frees, 40 bytes allocated.
==6742== For counts of detected errors, rerun with: -v
==6742== searching for pointers to 1 not-freed blocks.
==6742== checked 1360800 bytes.
==6742==
==6742==
==6742== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==6742==    at 0x1B904984: malloc (vg_replace_malloc.c:131)
==6742==    by 0x8048377: f (example.c:5)
==6742==    by 0x80483AC: main (example.c:12)
==6742==
==6742== LEAK SUMMARY:
==6742==    definitely lost: 40 bytes in 1 blocks.
==6742==    possibly lost:   0 bytes in 0 blocks.
==6742==    still reachable: 0 bytes in 0 blocks.
==6742==         suppressed: 0 bytes in 0 blocks.
==6742== Reachable blocks (those to which a pointer was found) are not shown.
==6742== To see them, rerun with: --show-reachable=yes

上面的C程序存在两个错误:1. 数组下标越界;2. 分配的内存没有释放,存在内存泄露的问题。对于错误1,看Valgrind的调试信息片断

==6742== Invalid write of size 4
==6742==    at 0x8048384: f (example.c:6)
==6742==    by 0x80483AC: main (example.c:12)
==6742==  Address 0x1B908050 is 0 bytes after a block of size 40 alloc'd
==6742==    at 0x1B904984: malloc (vg_replace_malloc.c:131)
==6742==    by 0x8048377: f (example.c:5)

对于错误2,看这个

==6742== malloc/free: 1 allocs, 0 frees, 40 bytes allocated.

......

==6742== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==6742==    at 0x1B904984: malloc (vg_replace_malloc.c:131)
==6742==    by 0x8048377: f (example.c:5)
==6742==    by 0x80483AC: main (example.c:12)

用Valgrind查找内存泄漏和无效内存访问

Valgrind是x86架构Linux上的多重用途代码剖析和内存调试工具。你可以在它的环境中 运行你的程序来监视内存的使用情况,比如C语言中的malloc和free或者C++中的new和delete。如果你使用了未初始化内存,在数组末端外 设置内存或是忘记释放指针,Valgrind都可以检测出来。尽管Valgrind还可以做其它的工作,本教程仍然集中在如何使用它来发现内存相关错误, 因为这也程序员经常出现的错误。
Windows用户不必沮丧,虽然在Windows上没有Valgrind可用,但是你可以试一试IBM的 Purify ,它在功能上和Valgrind相似。

获得Valgrind

如果你正使用Linux但却没有安装Valgrind,可以去 这里 免费下载一份。
安装过程非常简单,只需要用bzip2解压缩下载的软件包并将其展开即可(下面例子中的XYZ是版本号)。

bzip2 -d valgrind-XYZ.tar.bz2
tar -xf valgrind-XYZ.tar

或者用更简单的方法:

tar jxf valgrind-XYZ.tar.bz2

这会创建一个叫valgrind-XYZ的目录,进入该目录并运行

./configure
make
make install

好了,现在你已经安装了Valgrind,可以开始了解如何用它了。

用Valgrind查找内存泄漏

内存泄漏是最难发现的常见错误之一,因为除非用完内存或调用malloc失败,否则都不会导致任何 问题。实际上,使用像C或C++这类没有垃圾回收机制的语言时,你一大半的时间都花费在处理如何正确释放内存上。如果程序运行时间足够长,一个小小的失误 也会对程序造成重大的影响。
Valgrind支持很多工 具:Memcheck,Addrcheck,Cachegrind,Massif,Helgrind和Callgrind等。在运行Valgrind时, 你必须指明想用的工具。在这篇教程中,我们主要集中在内存检查工具上,它可以帮助我们检查内存使用情况(呵呵,其它工具我也不会用)。如果没有其它参 数,Valgrind在程序结束后给出关于free和malloc总共调用次数的简报:(注意,18490是进程号,你的机器上可能是其它值)

% valgrind --tool=memcheck program_name
...
=18515== malloc/free: in use at exit: 0 bytes in 0 blocks.
==18515== malloc/free: 1 allocs, 1 frees, 10 bytes allocated.
==18515== For a detailed leak analysis, rerun with: --leak-check=yes

如果程序中有内存泄漏的现象,内存分配的数量和内存释放的数量会不一致(你不能使用一个free调用来释放多个分配的内存)。
如果程序内存分配和释放的数量不一致,你可以加上leak-check参数重新运行程序,这样就可以看见分配了内存但却没有释放的代码。
为了演示这个功能,我写了一个简单的C程序并编译生成"example1"应用。

#include
int main()
{
char *x = malloc(100); /* or, in C++, "char *x = new char[100] */
return 0;
}

% valgrind --tool=memcheck --leak-check=yes example1

在运行结果中,给出了调用malloc却没有调用free的函数列表。

==2116== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1
==2116== at 0x1B900DD0: malloc (vg_replace_malloc.c:131)
==2116== by 0x804840F: main (in /home/cprogram/example1)

上 面的结果并没有告诉我们更多需要的信息,我们只知道在main函数中的malloc调用导致了内存泄漏,但并不知道是程序中的哪一行调用了malloc。 这是因为我们在编译程序时,没有给gcc加上-g参数,相关的调试信息就丢失了。重编一次再运行,我们就得到了更多的信息(片断)。

==2330== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1
==2330== at 0x1B900DD0: malloc (vg_replace_malloc.c:131)
==2330== by 0x804840F: main (example1.c:5)

现 在我们已经确切知道导致内存泄漏的是哪一行代码了。尽管知道在哪里释放内存仍然是一个问题,至少我们已经知道该从哪里入手。因为对每一次需要动态分配的内 存,你都有一个何时分配,何时释放的使用计划,既然已经知道导致内存泄漏的分配点,也就基本理清了内存的使用计划,有助于定位正确释放内存的位置。
在 加上--leak-check=yes参数后不再显示内存泄漏错误前,你可能需要重复修改代码很多次,一个优秀的,没有内存泄漏的软件就是这样诞生 的:-)。在运行Valgrind时加上--show-reachable=yes参数,可以找到每一个未来匹配的free或new,输出结果和上面差不 多,不过显示了更多未释放的内存。

用Valgrind查找无效指针使用

用memcheck工具,Valgrind也可以找出无效堆内存使用。比如,如果你用malloc或new分配了一个数组,并访问数组末端后面的内存:

char *x = malloc(10);
x[10] = ´a´;

Valgrind可以检测出这个错误。用Valgrind运行下面的示例程序:example2

#include

int main()
{
char *x = malloc(10);
x[10] = ´a´;
return 0;
}

%valgrind --tool=memcheck --leak-check=yes example2

其结果是(片断)

==9814== Invalid write of size 1
==9814== at 0x804841E: main (tst.c:6)
==9814== Address 0x1BA3607A is 0 bytes after a block of size 10 alloc´d
==9814== at 0x1B900DD0: malloc (vg_replace_malloc.c:131)
==9814== by 0x804840F: main (example2.c:5)

这 个信息表明我们分配了10字节的内存,但是访问了超出范围的内存,因此,我们就进行了一个´非法写´操作。如果试图从那块内存读取数据,我们就会得 到´Invalid read of size X´的警告(X是试图读取数据的大小,char是一个字节,而int根据系统的不同可能是2个字节或4个字节)。通常,Valgrind显示出函数调用栈 信息以方便我们准确定位错误。

检测使用未初始化变量

还有一类Valgrind可以检测的操作是在条件判断语句中使用未初始化变量。也许你应该养成在声明变量时就进行初始化的习惯,不过Valgrind仍然可以帮助你找出使用未初始化变量的地方。比如,运行下面代码生成的示例程序,example3

#include

int main()
{
int x;
if(x == 0)
{
printf("X is zero"); /* replace with cout and include
iostream for C++ */
}
return 0;
}

Valgrind会给出下面的结果(片断)

==17943== Conditional jump or move depends on uninitialised value(s)
==17943== at 0x804840A: main (example3.c:6)

Valgrind甚至可以知道如果一个变量被赋予一个未初始化的变量,这个变量仍然处于"未初始化"状态。比如运行下列代码:

#include

int foo(int x)
{
if(x < 10)
{
printf("x is less than 10/n");
}
}

int main()
{
int y;
foo(y);
}

Valgrind会给出下列警告:

==4827== Conditional jump or move depends on uninitialised value(s)
==4827== at 0x8048366: foo (example4.c:5)
==4827== by 0x8048394: main (example4.c:14)

你可能以为错误在foo中,和调用栈上的其它函数没有关系。但是因为main函数传递了一个未初始化值给foo,我们可以根据调用栈信息顺藤摸瓜,找到真正没有初始化变量的代码。
Valgrind仅仅有助于你在能够运行到代码中检测这些错误,请确信在测试中覆盖代码的每一个分支。

Valgrind还能发现什么?

Valgrind还能发现其它不正确使用内存的错误:如果你对同一块内存释放了两次,Valgrind就会探测到,而你则得到非法free的调用栈信息。
Valgrind 也能检测到使用不正确方法释放内存的错误。比如,在C++语言中有三种基本的内存释放方法:free,delete和delete[]。free函数应该 仅与malloc函数相对应--在一些系统上,你可能无须面对这个问题,但这样不具备可移植性。delete[]应该又只能和new[](分配数组)相对 应。(也许有些编译器允许你不去理会这些规则,但不能保证所有的编译器都允许你这样做,毕竟它不是标准的一部分。)
如果程序中存在这些问题,你会得到下列错误信息:

Mismatched free() / delete / delete []

这些错误都应该被立刻修复,即使你的程序偶然能够正常运行。

Valgrind不能查出哪些错误?

Valgrind不对静态数组(分配在栈上)进行边界检查。如果在程序中声明了一个数组:

int main()
{
char x[10];
x[11] = ´a´;
}

Valgrind则不会警告你!出于测试目的,你可以把数组改为动态在堆上分配的数组,这样就可能进行边界检查了。这个方法好像有点得不偿失的感觉。

更多告诫

使用Valgrind的负面影响是什么?它占用了更多的内存--可达两倍于你程序的正常使用量。如 果你用Valgrind来检测使用大量内存的程序就会遇到问题,它可能会用很长的时间来运行测试。大多数情况下,这都不是问题,即使速度慢也仅是检测时速 度慢,如果你用Valgrind来检测一个正常运行时速度就很慢的程序,这下问题就大了。
Valgrind不可能检测出你在程序中犯下的所有错误--如果你不检查缓冲区溢出,Valgrind也不会告诉你代码写了它不应该写的内存。

总结

Valgrind是x86架构上的工具,只能在Linux上运行(FreeBSD和NetBSD上 的相关版本正在开发中)。它允许程序员在它的环境里测试程序以检测未配对malloc调用错误和其它使用非法内存(未初始化内存)的错误以及非法内存操作 (比如同一块内存释放两次或调用不正确的析构函数)。Valgrind不检查静态分配数组的使用情况。
七 nm命令
nm命令 list symbols from object files
2006年07月09日 21:08

例:
nm -a a.out
nm -a func.o
list symbols from object files

例:
080480f4 ?
08048108 ?
08048128 ?
08048174 ?
08048254 ?
08048334 ?
08048350 ?
08048370 ?
08048378 ?
08048398 ?
080483b0 ?
08048400 t
08048590 ?
080485c0 r
080496e0 d
080496f0 ?
080496f4 ?
080497cc ?
080497d4 ?
080497dc ?
080497fc b
00000000 ?
00000000 ?
00000000 ?
00000000 ?
00000000 a
00000000 a
00000000 a
080496f4 A _DYNAMIC
080497dc A _GLOBAL_OFFSET_TABLE_
080485c4 R _IO_stdin_used
080497d0 ? __CTOR_END__
080497cc ? __CTOR_LIST__
080497d8 ? __DTOR_END__
080497d4 ? __DTOR_LIST__
080496f0 ? __EH_FRAME_BEGIN__
080496f0 ? __FRAME_END__
080497fc A __bss_start
080496e0 D __data_start
         w __deregister_frame_info
08048550 t __do_global_ctors_aux
08048450 t __do_global_dtors_aux
         w __gmon_start__
         U __libc_start_main@@GLIBC_2.0
         w __register_frame_info
080497fc A _edata
08049814 A _end
08048590 ? _fini
080485c0 R _fp_hw
08048398 ? _init
08048400 T _start
08048424 t call_gmon_start
080496ec d completed.1
00000000 a crtstuff.c
00000000 a crtstuff.c
080496e0 W data_start
080484b0 t fini_dummy
080496f0 d force_to_data
080496f0 d force_to_data
080484c0 t frame_dummy
08048424 t gcc2_compiled.
08048450 t gcc2_compiled.
08048550 t gcc2_compiled.
08048590 t gcc2_compiled.
08048500 t gcc2_compiled.
00000000 a init.c
080484f0 t init_dummy
08048580 t init_dummy
00000000 a initfini.c
00000000 a initfini.c
00000000 a long.c
08048500 T main
080497fc b object.2
080496e8 d p.0
         U printf@@GLIBC_2.0

top、grep、ftp等详解相关推荐

  1. FTP配置文件详解vsftpd.conf

    FTP配置文件详解vsftpd.conf 转载过来做个笔记,原文地址:https://blog.csdn.net/miss520jenny/article/details/92664533 #vi / ...

  2. CentOS7 安装配置FTP服务器详解

    CentOS7 安装配置FTP服务器详解 1.FTP简介 ftp(File Transfer Protocol文件传输协议)是基于TCP/IP 协议的应用层协议,用于文件的传输,包括ftp服务器(或服 ...

  3. 使用cmd上传指定文件到ftp服务器,命令行下的FTP使用详解

    命令行下的FTP使用详解 更新时间:2011年11月08日 11:59:51   作者: 今天新到一台服务器,需要做一些环境配置拷入一些备份数据,在这台服务器上装FlashFxp又觉得麻烦,所以干脆用 ...

  4. top与free命令详解

    top与free命令详解 top命令 top命令第一行 top命令第二行 top命令第三行 top命令第四行 top命令第五行 top命令第六行 free命令 top命令 在运维面试中top命令被问到 ...

  5. linux的ftp命令大全文库,linux下ftp命令详解

    linux下ftp命令详解 (11页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.9 积分 登录FTP服务器的命令格式:ftp [-v][-d][- ...

  6. top命令显示参数详解

    Linux中top命令详解 1. 前5行参数解析 2.进程信息列表区 3.特殊操作 top命令主要用来查看系统状况,CPU.内存.进程资源占用情况. 使用格式如下: top -d 10 //表示所打开 ...

  7. Linux 下 top 命令的使用详解

    前言: top 指令用于查看当前CPU负载, 内存占用. 或让其一直打印到固定文件内, 用于以后查看 版本: 本次 top 的版本为version 3.3.10, 系统版本为centos 7.4 使用 ...

  8. Linux中搭建一个ftp服务器详解

    来源:Linux社区  作者:luzhi1024 详解Linux中搭建一个ftp服务器. ftp工作是会启动两个通道: 控制通道 , 数据通道 在ftp协议中,控制连接均是由客户端发起的,而数据连接有 ...

  9. Linux grep/egrep命令详解

    grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来 grep搜索成功,则返回0,如果搜索不成功,则返回1,如果搜索的文件不存在,则返回2. grep的规则表达式( ...

  10. netstat -anu|grep 69命令详解

    首先说明netstat -anu|grep 69是两个命令,即netstat和grep命令. netstat命令详解: Netstat是控制台命令,是一个监控TCP/IP网络的非常有用的工具,它可以显 ...

最新文章

  1. Java项目:农资采购销售系统(java+SSM+Easyui+maven+Mysql)
  2. RxJava Rxandroid 结合 Retrofit 使用
  3. Just for fun——go实现一下观察者模式
  4. free命令里的buffers/cache
  5. xml 导入SQL Server 2005
  6. VMware 修复 View Planner中的严重RCE 漏洞
  7. java中sam接口_具有非SAM接口的lambda的Java习惯用法
  8. FFmpeg和WebRTC
  9. CCF 201809-2 买菜
  10. c2c运营流程图_电商运营流程图模板分享,运营的核心都在这里了,快来拿走吧...
  11. 学生学籍管理系统课程设计报告书
  12. 写给自己的一封信--平顶山学院20届计科学生大学两年成长经历回忆
  13. cdrom是什么意思_开启电脑时出现CDROM是什么意思
  14. 计算机主机自动关机如何设置,电脑怎么设置自动关机?电脑自动关机方法教程 电脑维修技术网...
  15. 做产品,懂人性,触人心
  16. python字典一键多值_python一键多值
  17. 2020一个诗人的新年计划
  18. 文科生可报考那些计算机学校,文科生/600分以上可以报考哪些学校?
  19. 博通wifi 芯片配置工具wl 详解
  20. 七夕送礼必备好物,品质好的蓝牙耳机分享

热门文章

  1. CAD二次开发 Drawjig 动态的改变文字的大小及位置
  2. 用PHP实现九九乘法表
  3. php下一代的五个framework介绍
  4. 微机----------------可编程并行接口8255A
  5. 基于k8s、docker、jenkins构建springboot服务
  6. 简单的局域网共享硬盘,尚未解决,记录一把
  7. [喵咪大数据]Hbase搭建和基本使用
  8. 饿了么的 PWA 升级实践 - 推酷
  9. 【集创赛】arm杯国奖作品推荐--作品介绍!
  10. cocos2d-x横版格斗游戏教程1