一、top的概念

top是linux下一个用户态工具,和windows下任务管理器差不多,就是实时显示linux系统运行状态,进程线程cpu占用,内存使用情况等等。可以实时动态地查看系统的整体运行情况,是一个综合了多方信息检测系统性能和运行信息的实用工具。

二、top在哪里获取?

(1)如果是发行版的linux,top由procps组件提供,procps是内核proc utils工具集,其中不仅包含了top命令,还有我们熟知的ps,kill,free等命令都源于procps组件,CGEL6x的yocto downloads目录下也有procps,可以解开看看。

(2)如果是嵌入式linux,一般由busybox提供,相对比服务器版的top,功能会偏弱一些。a tiny top

三、top的版本

先来看下服务器上的top,命令行下敲打:top -v

-bash-4.2$ top -v
procps-ng version 3.3.9
Usage:
top -hv | -bcHiOSs -d secs -n max -u|U user -p pid(s) -o field -w [cols]
-bash-4.2$

从输出信息中,我们可以看出top的版本 其实就是procps-ng的版本,版本号为:3.3.9,后面为啥带个ng,啥意思,我们顺带随追溯下procps工具的历史。

最开始procps工具的maintainer很少有时间去处理procps,不知道为啥,反正一开始procps项目维护的并不好,在1997年的时候,Albert Cahalan为procps包写了一个新的ps程序,但随后几年里,Albert Cahalan一直悄悄的帮助debian packet maintainer修复bug,直到2001年,因为缺少维护者,Rik van Riel决定要为procps搞点事情,他在红帽公司的CVS上将旧的代码重新捡起来,并开始添加补丁,与此同时,一些开发者也以不同的形式开始添加patch。

到了2002年,Albert Cahalan把procps项目放到了http://procps.sourceforge.net,并设置procps的主版本号为3,一部分原因是他不想遗失之前的功能测试和bug fix,另一方面原因是top的源码已经被重写了,

后来procps.sourceforge.net停了,项目移动到了http://gitorious.org/procps,http://gitlab.com/procps-ng/procps,这个时候,Debian,Fedora,openSUSE开始fork这个项目,此时procps项目被重新命名为procps-ng(next-generation),版本号变更成了3.3.0,同时库的名称由libproc.so变成libprocps.so。

OK,ng就是下一代的意思,瞬间似乎明白了很多软件包的含义,libcap-ng,netsniff-ng

那top这个名字是啥意思?高高的 ? 顶部? 和任务管理器有啥关系,实际上是table of processes,主要是用来描述进程的。展示进程的自身属性及资源使用情况,如cpu占用,内存占用,运行状态。本文就是这么专!不放过一个技术细节,即使是程序命名也要追溯其来源、含义!

四、top原理?

就是借助于操作系统内核暴露出来的proc接口,top程序来进行数据统计,并以终端形式进行展示。

主要接口:/proc/pid/stat、/proc/stat、/proc/uptime、/proc/meminfo

五、Top全字段分析

好了,说了一大堆无关紧要的,直奔主题吧,看一下top的输出格式及字段详解,并以实际程序来动态调整每个字段的输出结果,直观感受下各字段的作用,眼见为实。

先来个top全景:

各部分含义:

①系统时间字段

图中字段含义:系统时间,当前时间为14:03:20

系统时间,可以通过date -s命令来修改。如:date -s 10:10:10

系统时间设置与读取分别由syscall(time)和syscall(settimeofday)系统调用来设置,并通过/etc/localtime文件进行时区转换。

修改一把:

[root@localhost top]# date -s 04:33:52

Fri Jun  8 04:33:52 CST 2018

来观察下top:

还原当前时间:

[root@localhost top]# date -s 14:34:26

Fri Jun  8 14:34:26 CST 2018

在观察下top效果:

②系统运行时间字段

 

图中字段含义:系统从上电运行时长为14天15小时,这期间未发生断电。

系统运行时间由/proc/uptime提供,这个时间的变动不好做实验,因为这个时间是只读的,本身就不应该让人为去设置。据说这个程序,可以通过获取内核的uptime_proc_fops结构体地址,然后进行数据篡改。更改uptime的运行时间,制造假象!这个hack行为就暂时不做实验了。

https://github.com/dkorunic/uptime_hack/blob/master/uptime_hack.c

③当前系统用户数字段

 

图中字段含义:当前有84个用户。

来个实验:

新建一个ssh链接到服务器,ssh yuchen@10.74.154.170,可以看到top中user会增加一个。

将ssh终端断开连接:在看下top:

实际上users用户数的统计由/var/run/utmp给出数据。

④系统负载

 

图中字段含义:3个字段分别表示系统最后1分钟,5分钟,15分钟,系统负载情况,数值越高说明负载越严重。

因为给出了过去时刻的3个字段,如果你看到1分钟的负载较高,但是15分钟的负载并不高,那么可能代表有一小段时间在进行cpu密集型计算,系统宏观上还是正常的,loadavg可作为系统忙时调试的一种数据参考。

来模拟下高负载:

创建256个任务同时跑,观察top情况。

先看一下空闲时,系统top情况:可以看到基本上都是0.x,基本都是空闲状态,运行良好。

程序代码:(这段代码用于创建loop程序,后面会经常用到)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/syscall.h>
#define MAX_PTHREAD_NUM 256
void pthread_func(void *args)
{printf("create pthread task! pid: %d\n", syscall(__NR_gettid));while(1);
}
int main(int argc, char **argv)
{int i, n = 1;pthread_t tid[MAX_PTHREAD_NUM];if(argc == 2)n = atoi(argv[1]);for(i=0; i<n; i++)pthread_create(&tid[i], NULL, (void*)pthread_func, NULL);for(i=0; i<n; i++)pthread_join(tid[i], NULL);while(1);return 0;
}

创建256个任务,启动程序,观察top:

[root@localhost top]# ./a.out 256

reate pthread task! pid: 18245

create pthread task! pid: 18106

create pthread task! pid: 18137

………………

………………

create pthread task! pid: 18237

create pthread task! pid: 18241

随着时间的推移,loadavg的值开始升高,1分钟的loadavg增长最快,5分钟loadavg增长缓慢,15分钟loadavg增长最慢。

按下大H,展开线程,可以看到系统中有大量任务在运行。

运行了2分钟的测试程序。Loadavg的值已经达到9.x, 5.x, 2.x,Top如下:

停止测试程序,loadavg开始缓慢降低。一分钟loadavg下降最快,5分钟其次,15分钟下降最慢。

一分钟过后,loadavg值已经变成了0.x

Ok,loadavg就是这么个东西,loadavg显示了1,/5/15分钟系统负载情况。

另外,在busybox中的top,loadavg的显示这样的:

Loadavg后面多出2个字段,2/135 和 1168

2表示:当前系统中运行的任务数,(R)。

135表示:系统总任务数。

1168:系统最近一次启动的任务pid

⑤Tasks行表示系统任务情况,(分别代表:任务总数,正在运行任务数,睡眠任务数,停止任务数,僵尸任务数)

图中字段依次含义:任务总数,正在运行任务数,睡眠任务数,停止任务数,僵尸任务数。可以看到总共有320个任务,1个任务运行,319个睡觉,0个停止,0个僵尸。

运行任务(R):获取cpu在执行。

睡眠任务(S/D):等待资源或信号到来,睡觉。

停止任务(T):任务处于stop状态,发送continue signal可以让其继续运行。

僵尸任务(Z):任务已经挂了,其父进程未收尸。

进程状态之--→ R

R:事实上,在内核态中,挂在cpu的运行队列上的任务都是R状态。但是处于R状态并不代表你拿到了cpu控制权。运行任务可能有多个,但是实实在在能在cpu运行的只有一个(单核系统)。所以,R任务代表你所有资源都已具备,时刻等待cpu调度。但也可能你连cpu都拿到了,那你就是真正的running!!

测试程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/syscall.h>#define MAX_PTHREAD_NUM  256
void pthread_func(void *args)
{printf("create pthread task! pid: %d\n", syscall(__NR_gettid));while(1);
}int main(int argc, char **argv)
{int i, n = 1;pthread_t tid[MAX_PTHREAD_NUM];if(argc == 2)n = atoi(argv[1]);for(i=0; i<n; i++)pthread_create(&tid[i], NULL, (void*)pthread_func, NULL);for(i=0; i<n; i++)pthread_join(tid[i], NULL);while(1);return 0;
}

创建4个loop任务,观察top:

Top -H输出如下,可以看到有5个R状态任务,4个测试程序+top程序,总cpu使用率为400%。这4个测试程序分别瓜分了4个cpu核,每个任务实实在在的处于Running状态,每个程序占用100%cpu。

再次启动4个loop任务,这次将4个任务绑定到一个cpu核上执行。看看结果:

Top输出如下,通过cpu绑核后,可以看到总cpu占用率只有100%,每个程序占用≈25%。但是我们看到这个4个任务还是处于R状态,但事实上,同一时刻只能存在一个真正运行的任务。所以说R状态有两种情况,一种是已经就绪了,随时可以运行,但尚未抢到cpu,另一种情况是真正的在cpu上执行。在操作系统眼里,这些任务都是R状态。所以,如top输出所示,CPU1核上,R状态任务有4个,但实际上真正运行只有1个。

进程状态之--→ S

S:缺少某种资源或等待事件完成,处于睡眠状态,等待被唤醒。进程也可以自己主动让住cpu,进入睡眠状态。该状态可以通过信号signal唤醒。

测试程序:

int main()
{printf("I'm a sleep task!\n");while(1) {sleep(100);}
}

睡眠任务运行:

Top输出:

可以看到长期处于睡眠态,由于是浅度睡眠可以接收信号,我们向进程发送信号kill -9 8337,可以看到进程8337被干掉,因为进程接收到sigkill信号后,被唤醒执行默认的信号处理程序,程序退出了。

进程状态之--→ D

D:disk sleep,是一种深度睡眠,通常是在等待io、磁盘。与S状态相比它不能通过信号唤醒。处于这种状态的进程必须拿到资源才能唤醒,否则一直睡觉,Kill -9也白扯。

通常系统里不会长期出现D状态任务,如果长期出现D状态任务,多半是系统已经发生了问题。所以这个实验不好做,看来又要搞破坏了。

找一块嵌入式单板,在其linux系统中mount一个nfs文件系统,mount后将网线断开,此时df -h会卡死,长时间不能返回,事实上df进程已经处于D状态,正在等待io资源完成,io源于网络,此时网络已经断开!

我们telnet登陆到单板上看下情况,可以看到df -h确实处于D状态了!额外看到D后面有个+号,是什么鬼?代表前台进程,下篇文章会解释。

此时的D状态任务像僵尸一般驻留在系统体内,不接收任何信号,ctrl+c、ctrl+z通通白废!

Kill -9 3380,kil -2 3380,向进程发信号也是如此。

我们再次接上网线,稍等片刻,系统输出nfs:server 192.168.1.168 ok字样,df -h重新复活了!串口又可以接收指令了。可见,D状态任务只有io资源满足的时候才能复活啊!

进程状态之--→ T

T:该状态表示进程处于停止状态。通常用于作业控制(job control),停止状态并不是说进程已经终止了,而是一个临时停止,举个例子:我们手机正在运行一个qq音乐进程,我们在房间内享受着优美的音乐,突然窗外传来一阵异样的噪音,这个时候我们赶紧把qq音乐暂停,爬在窗口看看是什么情况,原来是广场舞大妈们正在操练,好吧没什么大不了的,关上窗,继续播放qq音乐。当我们去看窗户的这段时间,qq进程就处理暂停状态,它并没有真的停止,也就是T状态。那么linux进程什么时候会进入T状态呢?有一种常见的方法让进程暂停执行,强制处于T状态,那就是CTRL+Z命令,该命令会让进程暂停执行。fg/bg命令让其恢复。稍后会用程序表明。另外,大家都知道gdb吧,有了T状态,我们就可以利用这个状态进行调试了,gdb在使用break设置断点的时候,实际上就是发一个stop信号给进程,让进程暂停,暂停后我们可以观察进程运行状态,变量值,等等信息,达到调试程序的功能。按下r键可以让程序继续运行,而这相当于给程序发了一个sigcont信号(继续运行)。单步调试也是同样的道理。

实验:

启动一个loop任务,让其暂停执行。

Top -p 8713看下任务状态,显示任务已经处于T状态。

Fg将任务再次唤醒,得到运行。

Tip:我们在编译yocto或者大型android类软件时,通常会耗时很久,这个时候我们想在编译的过程中,干点别的事,假如使用Ctrl+c来结束当前程序的执行。那么下次必须重新启动编译。但是如果是ctrl+z,只是先将任务暂停,爽完了,fg唤醒即可。

进程状态之--→ Z

Z:表示进程处于僵尸状态。什么?僵尸?系统里出现了这样的进程还能了得?事实上不用害怕,僵尸状态只是子进程退出时的一种临界状态,它并不可怕,处于僵尸态的进程所有占用资源已经释放(除了task_struct这个结构变量),留下task_struct结构,是为了让父进程知道子进程的死亡原因,来进行合适的处理。进程退出码保存在task_struct->exit_codel;父进程需要调用wait/waitpid来为子进程收尸,一旦wait系统调用后,子进程会从此消失。通常情况下系统中不会有Z状态进程,如果有,也不用怕,那就是父进程还没有来得及进行收尸。另外Z进程也是无法接收信号的。假如你看到系统里有个僵尸进程,你看着很不爽,你用kill -9来杀这个进程,是没有任何效果的,因为它已经死了,,只剩个躯体在那,你kill -9无非是在尸体上在多捅几刀,无任何意义。

创造一个僵尸程序:

void child_process()
{printf("I'm child process! pid=%d\n", getpid());sleep(1);_exit(0);
}int main()
{int pid;int status;pid = fork();if(pid == 0) {child_process();} else {while(1);waitpid(pid, &status, 0);}
}

父进程创建一个子进程,子进程打印自己的pid,并退出,但父进程一直不去调用waitpid为子进程收尸,看看运行结果:

运行Top -p 9053,可以看到系统中有僵尸了!Zombie处于Z状态。

将父进程结束掉,子进程也随之退出。想想这是为什么?

top工具全字段解析+实战(一)相关推荐

  1. clickhouse原理解析与开发实战 pdf_重识SSM,“超高频面试点+源码解析+实战PDF”,一次性干掉全拿走...

    重识SSM,"超高频面试点"+"源码解析"+"实战PDF",一次性干掉全拿走!! 01 超高频面试点知识篇 1.1 Spring超高频面试点 ...

  2. iis日志字段解析 网站运维工具使用iis日志分析工具分析iis日志(iis日志的配置)

    网站运维工具使用iis日志分析工具分析iis日志(iis日志的配置) https://www.cnblogs.com/fuqiang88/p/5870306.html 我们只能通过各种系统日志来分析网 ...

  3. 基于神策用户画像,在线教育企业线索标签体系搭建及培育全流程解析

    作者介绍:TigerHu,环球网校大数据营销产品 leader,主导数据产品线和营销 CRM 产品线. 本文内容均从作者真实实践过程出发,结合作者公司与神策数据合作真实场景,从神策用户画像产品出发,全 ...

  4. 《Spring Boot+Vue全栈开发实战》读书笔记

    写在前面 嗯,回家处理一些事,所以离职了,之前的公司用开源技术封装了一套自己的低代码平台,所以之前学的spring Boot之类的东西都忘了很多,蹭回家的闲暇时间复习下. 笔记整体以 Spring B ...

  5. ChatGPT全栈开发实战:从需求分析到数据可视化,一站式指南助你快速构建全面应用

    <ChatGPT全栈开发实战:从需求分析到数据可视化,一站式指南助你快速构建全面应用>是一本旨在引领我们进入全栈开发世界的综合指南.通过结合强大的ChatGPT技术和全栈开发的实践,我们将 ...

  6. 全栈开发实战(一)——简易博客社区后端搭建教程(附源码)

    全栈开发实战(一)--简易博客社区后端搭建 项目展示视频 项目Github地址 (一)项目准备 在项目开始前,首先确保你已安装好Go语言并配置好Go语言编辑器,同时安装好MySQL或其他数据库,其次, ...

  7. jvm调优五:jvm调优工具和调优实战

    jvm调优工具和调优实战 jvm自带常用命令 JPS jps是用于查看有权访问的hotspot虚拟机的进程id. 当未指定hostid时,默认查看本机jvm进程id -l:输出完整jar名称 -v:输 ...

  8. 全栈开发实战 | SSM框架整合完整教程

    "一个人最好的状态:梦想藏在心里,行动落于腿脚." 目录 1.前言 2.基本概念 2.1 MyBatis 2.2 Spring 2.3 SpringMVC 3.开发环境搭建 3.1 ...

  9. Spark ALS recommendForAll源码解析实战之Spark1.x vs Spark2.x

    文章目录 Spark ALS recommendForAll源码解析实战 1. 软件版本: 2. 本文要解决的问题 3. 源码分析实战 3.1 Spark2.2.2 ALS recommendForA ...

  10. Web项目,网页上传excel文件并解析实战示例

    最近写了一个基于poi解析excel文件的工具类,所以想在web项目中测试一下,就做了这个简单的项目.本项目主要使用了 SpringMVC+RESTful+Maven的风格.适合有一定基础的人员. 源 ...

最新文章

  1. Mac下安装JDK以及怎么配置环境变量?
  2. maven中snapshot版本和正式版本的区别
  3. 定制CentOS (Redhat AS 5.1)安装盘
  4. [Codevs] 1001 舒适的路线
  5. 网络犯罪分子为何针对中小企业?—Vecloud微云
  6. 遍历Map的几种方式以及性能小结
  7. 06丨MongoDB基本操作
  8. 光栅图形学算法基础其二 (裁剪算法)
  9. 【codevs1026】逃跑的拉尔夫
  10. HDU 4283:You Are the One 区间DP好题
  11. java大数据与python大数据如何选择?
  12. 数字图像处理-直方图均衡化,直方图规定化
  13. [UE]EpicGames Launcher 添加/识别本地已有编辑器版本
  14. linux 设置u盘为只读模式,U盘如何设置为只读模式
  15. Synchronized 同步锁详解
  16. 真兰仪表通过深交所注册:拟募资17.4亿 上半年净利下降27%
  17. 记录一次Specified key was too long的问题
  18. 凡客副总裁崔晓琦离职 曾负责旗下V+商城项目_科技_腾讯网
  19. 三星4k3d电视测试软件,说出来你可能不信:3D、4K、曲面电视慎重购买
  20. 解决iOS 上拉边界下拉出现白色空白

热门文章

  1. php 降低采样率,讨论采样频率、采样深度(位深)、音量调节对音质的影响
  2. 46泰勒中值定理的常规证明
  3. 浅析桌面虚拟化给企业带来的价值
  4. 访问网站提示:您未被授权查看该页恢复办法
  5. Taylor Swift - Enchanted_20131123141153-pdf
  6. 听某个老师的ElasticSearch记的笔记了
  7. php实现前后端完全分离
  8. 安然公司特殊目的实体(SPEs)解读
  9. web前段设计之痛:手机浏览器和pc浏览器的width:100%的自适应问题
  10. Matlab计算矩阵的行列式