2020-01-25 23:10:03 TanGuozheng_Java 阅读数 375

Linux中使用命令查看进程

在Linux中使用PS命令查看进程

-a,查看所有

-ef,以全格式显示进程所有信息,包括父进程Pid,创建人,创建时间,进程号。等等

-u,以用户(user)的格式显示

-x, 显示后台进程运行参数

Linux常用命令实用

Linux系统中,一般情况下,我们是通过这样的语句去查询的进程

1、ps -a

ps -a|grep redis

 可以查看到这样的内容

2、ps -ef

ps -ef|grep redis

能够查询这样的结果

2019-12-03 11:35:40 qq_42650346 阅读数 30

1-1关于Linux的进程详述

之所以希望对Linux有一个尽可能全面地了解,是因为我认为进程是Linux中非常重要的一环。

本章将了解以下内容:

1.什么是进程?

2.进程和程序有何区别?

3.进程知识的一些拓展

4.关于线程控制


1.什么是进程

进程是进程是程序在一个数据集合上的一次执行过程。
广义的进程其实有许多概念:
进程是一个独立的可调度的活动;
进程是一个抽象实体,当它执行某个任务时,要分配和释放各种资源;
进程是可以并行执行的计算单位;
进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动;

2. 进程和程序有何区别?

2.1 概念

  程序(procedure):程序就是执行一系列有逻辑、有顺序结构的指令,帮我们达成某个结果。我(或者说系统)对于它的期望就是:这个操作有什么效果。比如考试,老师给你一张试卷->你开始做->老师看到你的成绩,考试就是程序,你需要执行,写了就有分数,哪怕零分。
  进程(process):进程是程序在一个数据集合上的一次执行过程,在早期的UNIX、Linux 2.4及更早的版本中,它是系统进行资源分配和调度的独立基本单位。就如上面的考试(程序),老师让你考试你执行了一个考试的程序,你做了“听力”这个进程,又做了“单项选择题”这个进程,还做了“作文“这个进程。你需要一步一步来,一题一题做。
  为了方便理解,可以简而言之:程序是为了实现某种任务而设计的软件。进程?进行中的程序。

2.2 进程的特性

  程序只是一些列指令的集合,是一个静止的实体,而进程不同,进程有以下的特性:
(1)动态性:进程的实质是一次程序执行的过程,有创建、撤销等状态的变化。而程序是一个静态的实体。
(2)并发性:进程可以做到在一个时间段内,有多个程序在运行中。程序只是静态的实体,所以不存在并发性。
(3)独立性:进程可以独立分配资源,独立接受调度,独立地运行。
(4)异步性:进程以不可预知的速度向前推进。
(5)结构性:进程拥有代码段、数据段、PCB(进程控制块,进程存在的唯一标志)。也正是因为有结构性,进程才可以做到独立地运行。

2.3 进程的分类

  在Linux系统中,根据进程的特点,把进程可以分为三类:交互进程、批处理进程和守护进程。
  交互进程:是由shell启动的进程,它既可以在前台运行,也可以在后台运行。交互进程在执行过程中,要求与用户进行交互操作。简单来说就是用户需要给出某些参数或者信息,进程才能继续执行
  批处理进程:与windows原来的批处理很类似,是一个进程序列。该进程负责按照顺序启动其它进程。
  守护进程:是是执行特定功能或者执行系统相关任务的后台进程。守护进程只是一个特殊的进程,不是内核的组成部分。许多守护进程在系统启动时启动,直到系统关闭时才停止运行。而某些守护进程只是在需要时才会启动,比如FTP或者Apache服务等,可以在需要的时候才启动该服务。
  根据进程的状态又可以将其分为:守护进程、孤儿进程和僵尸进程(《在UNIX高级环境编程》书中也称为”僵死进程“)。
  守护进程:所有守护进程都可以超级用户(用户ID为0)的优先权运行;守护进程没有控制终端;守护进程的父进程都是init进程(即1号进程)。
  孤儿进程:一个父进程退出后,它的一个或多个子进程还在运行,那么这些子进程将成为孤儿进程(没有爸爸,要找个后爸ヽミ ´∀`ミノ<管着它)。孤儿进程将被init进程所收养,并由init进程对它们完成状态收集工作。
  僵尸进程:一个子进程结束但是没有完全释放内存(在内核中的 task_struct没有释放),该进程就成为僵尸进程。僵尸进程会导致资源的浪费,而孤儿进程不会。关于孤儿进程和僵死进程会开一版贴来进一步认识。

3.进程拓展

  进程有父子之分,那父子进程如何实现关系?
  进程产生子进程由fork(vfork)创建。fork是一个系统调用,其效果是为当前进程创建一个新进程,此子进程(新进程)除了父进程的返回值和PID外都是一样的,如进程的文件描述、寄存器等等。vfork可以使的效率得到大幅度提升。
  另一个系统调用exec() ,作用是切换子进程中的执行程序也就是替换其从父进程复制过来的代码段与数据段。
  以下为简短的代码演示使用fork创建子进程:

int      glob = 6;      /* external variable in initialized data */
char     buf[] = "a write to stdout\n";

int main(int argc, char const *argv[])
{
	int      var;       /* automatic variable on the stack */
	pid_t    pid;

	var = 88;
	if (write(STDOUT_FILENO, buf, sizeof(buf) - 1) != sizeof(buf) - 1)
		err_sys("write error");
	printf("before fork\n");   /* we don't flush stdout */
	if ((pid = fork()) < 0)    /*(1)*/
	{
		err_sys("fork error");
	}
	else if (pid == 0)         /* child */   /*(2)*/
	{
		glob++;                /* modify variables */
		var++;
	}
	else                       /*(3)*/
	{
		sleep(2);              /* parent */
	}
	printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
	exit(0);
}   //摘自《UNIX高级环境编程第二版》

  毋须多关心代码除了(1)、(2)、(3)的其他内容。在(1)处创建子进程。在fork函数调用之后,新的进程将启动并和本进程一起从fork函数返回。但不同的是本进程的fork将返回新任务的pid,而新进程的fork将返回0。(注意就算创建成功,也还没有走相关的程序,需要exec())。
  关于运行中的进程,我们可以通过进程树来方便的查看其父子关系。系统提供了进程树查看工具“tree”。去下查看树指令“pstree”:

systemd─┬─ModemManager─┬─{gdbus}
        │              └─{gmain}
        ├─NetworkManager─┬─dhclient
        │                ├─dnsmasq
        │                ├─{gdbus}
        │                └─{gmain}
        ├─VGAuthService
        ├─accounts-daemon─┬─{gdbus}
        │                 └─{gmain}
        ├─acpid
        ├─agetty
        ├─apt.systemd.dai───apt.systemd.dai───unattended-upgr
        ├─aptd───{gmain}
        ├─avahi-daemon───avahi-daemon
        ├─colord─┬─{gdbus}
        │        └─{gmain}
        ├─cron
        ├─cups-browsed─┬─{gdbus}
        │              └─{gmain}
        ├─cupsd
        ├─dbus-daemon
        ├─fwupd─┬─3*[{GUsbEventThread}]
        │       ├─{fwupd}
        │       ├─{gdbus}
        │       └─{gmain}
        ├─gnome-keyring-d─┬─{gdbus}
        │                 ├─{gmain}
        │                 └─{timer}
        ├─lightdm─┬─Xorg───{InputThread}
        │         ├─lightdm─┬─upstart─┬─at-spi-bus-laun─┬─dbus-daemon
        │         │         │         │                 ├─{dconf worke+
        │         │         │         │                 ├─{gdbus}
        │         │         │         │                 └─{gmain}
        │         │         │         ├─at-spi2-registr─┬─{gdbus}
        │         │         │         │                 └─{gmain}

  可以直观地看到所有进程起始于“systemd”(另外一种是init),其即是所有进程的父进程或者祖父进程(简单记忆就是爸爸的爸爸)。
  我们也可以使用<ps -fxo user,ppid,pid,pgid,command>来进一步确认进程的父子关系。pid即该进程的唯一标号,ppid即其父进程编号,command 表示的是该进程通过执行什么样的命令或者脚本而产生的。通过查看此表就可以知道ps是由bash 创建的。

USER       PPID    PID   PGID COMMAND
apical-+  21070  21071  21071 bash
apical-+  21071  23394  23394  \_ ps -fxo user,ppid,pid,pgid,command
apical-+  16212  16213  16213 bash
apical-+  15848  15849  15849 bash
apical-+  15766  15767  15767 bash
apical-+  14318  14319  14319 bash
apical-+  13738  13739  13739 bash
apical-+  13333  13334  13334 bash
apical-+   1708   2646   2646 /sbin/upstart --user
apical-+   2646   2711   2709  \_ upstart-udev-bridge --daemon --user
apical-+   2646   2724   2724  \_ dbus-daemon --fork --session --addres
apical-+   2646   2736   2736  \_ /usr/lib/x86_64-linux-gnu/hud/window-
apical-+   2646   2767   2765  \_ upstart-dbus-bridge --daemon --sessio
apical-+   2646   2768   2766  \_ upstart-dbus-bridge --daemon --system
apical-+   2646   2770   2769  \_ upstart-file-bridge --daemon --user
apical-+   2646   2774   2773  \_ /usr/bin/fcitx
apical-+   2646   2788   2788  \_ /usr/bin/dbus-daemon --fork --print-p
apical-+   2646   2794   2793  \_ /usr/bin/fcitx-dbus-watcher unix:abst
apical-+   2646   2801   2801  \_ /usr/lib/x86_64-linux-gnu/bamf/bamfda

  完整地了解UNIX的进程控制是非常重要的。其中必须熟练掌握的只有几个函数–fork 、exec_族、_exit、wait和waitpid 。很多应用程序都使用这些原语。fork原语也给了我们一个了解竞争条件的机会。往后的文章逐步对这些函数进行学习。

参考:https://www.jianshu.com/p/b96f0c3d2d36
   https://blog.csdn.net/qq_36812792/article/details/80118923

2015-09-18 11:13:22 XJH0918 阅读数 488
获取ID
#include <stdio.h>
#include <unintd.h>
#inlcude <stdlib.h>
pid_t getpid(void)//获取本进程的ID
//printf("PID=%d\n",getpid());
pid_t getppid(void)//获取父进程
//printf("PID=%d\n",getppid());

进程的创建--fork
//fork:子进程和父进程拷贝数据段
pid_t fork(void);
//fork在于它被调用一次,则是有返回两次,并且有三种不同的返回值
//在父进程中,fork返回的是子进程的ID号
//在子进程中,fork返回的是零
//如果出错,则是会返回负值
//#include <stdio.h>
//#include <stdlib.h>
//int main(void)
{
//pid_t pid;
//int count=0;
//pid=fork();
//count++;
printf("count=%d\n",count);
}
输出的结果:count =1
                   count=1
分析:有两次结果输出,是因为fork创建子进程是,父进程先执行;接着子进程执行都有返回值;第一次和第二次结果都是1的原因:父进程在执行完之后,输出的结果是1;对子进程来说,fork出来之后,和父进程之间可以进行代码的拷贝,而不是数据,所有在子进程执行count++时,它的初值是0的。
-----------------------------------------------------------------------------------
创建进程--vfork
//子进程和父进程共享数据段
//#include <stdio.h>
//#include <stdlib.h>
//int main(void)
{
//pid_t pid;
//int count=0;
//pid=fork();
//count++;
printf("count=%d\n",count);
}
输出:count =1//子进程先执行
            count=2//父进程执行
--------------------------------------------------------
exec函数族
//exec用于被执行的程序替换调用它的程序
int execl(const char *path,const char argn1,...)
//path 含完成的目录路径
//arg1---argn代表的是被执行程序所需要的参数,含函数名,最后需要以NULL结束
//execl("/bin/ls","ls","-al","/etc/password",(char*)0);
-----------------------------------------------------------
int execp(const char *path,const char arg1...)
//path:被执行程序的目录,不需要包含完整的路径
execp("ls","ls","-al","/etc/password",(char*)0);
//第一个“ls”代表的是执行程序的名字,第二个"ls"表示的是指令
---------------------------------------------------------------------
int execv(const char *path,const char argv[])
//path 含完成的目录路径
--------------------------------------------
进程的等待
//#include <stdio.h>
//#inlcude <sys/wait.h>
//#inlcude<sys/types.h>
//pid_t wait(int *status)
例子:
#int main
{
    pid_t pc,pr;
    pc=fork();
    if(pc==0)//如果是子进程
    {
        printf("child fork %d!\n",getpid());
        sleep(10);
    }
    else if (pc>0)//如果是父进程
    {
        pr=wait(NULL);
        printf("i catch a child process with pid of %d\n",pr);
    }
}
输出结果:child fork..
                    i catch a child process with...
2017-11-22 12:48:39 m0_38121874 阅读数 1491

一、进程创建
1、初识fork()函数
在Linux中,fork函数是非常重要的函数,它从已存在的进程中创建一个新进程。这样,新进程为子进程,原进程为父进程。
(1)调用fork函数的格式,如下:

#include <unistd.h>
#include <sys/types.h>
pid_t fork(void);
返回值:子进程返回0;父进程返回子进程的PID;出错返回-1

(2)调用fork函数后,内核的工作:
1)分配新的内存块和内核数据结构给子进程。
2)将父进程的部分数据结构内容拷贝至子进程。
3)添加子进程到系统进程列表中。
4)fork返回,调度器开始调度。
总之:子进程是父进程的一个副本,将获得父进程的数据段、代码段、用户段、堆、共享库和文件描述符。由于具有相同的文件描述符,所以子进程可以读写父进程中的任何文件。

注意:当一个进程调用fork之后,就有两个二进制代码相同的进程,而且它们都运行到相同的地方,但是每个进程都可以开始它们自己的旅程。也就是说,fork被调用一次,返回两次。看如下程序:

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
    pid_t pid;
    printf("Before: pid is %d\n", getpid());
    if((pid=fork()) == -1)perror("fork()"),exit(1);
    printf("After:pid is %d, fork return %d\n", getpid(),pid);
    sleep(1);
    return 0;
}

运行结果:
这里写图片描述

释:
这里有三行输出,一行before,两行after。进程2785先打印before信息,然后再打印after,另一个after由2786打印。但是,进程2786没有打印before,为什么呢?因为,fork之前,父进程独立执行;fork之后,父子进程两个执行流分别执行。

注意:
fork之后谁先执行,完全由调度器决定。

2、存储方式:写时拷贝
通常,父子进程代码共享,父子进程不再写入时,数据也是共享的。当任意一方试图写入,便以写时拷贝的方式各自存有一份副本。

3、fork常规用法:
(1)一个父进程希望赋值自己,是父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求。
(2)一个进程要执行一个不同的程序。例如,子进程从fork返回后,调用exec函数。

4、fork调用失败的原因
(1)系统中有太多的进程。
(2)实际用户的进程数超过了限制。

5、vfork函数
(1)用于创建一个子进程,而子进程和父进程共享地址空间,fork的子进程具有独立的地址空间。
(2)vfork保证子进程先执行,在它调用exec或(exit)之后父进程才可能被调度运行。

【例】

#include<stdio.h>
#include<stdlib.h>

int glob = 0;
int main()
{
    pid_t pid;
    if ((pid=vfork()) == -1)perror("fork"),exit(1);
    if(pid == 0){//child
      sleep(1);
      glob = 6;
      printf("child glod %d\n", glob);
      exit(0);
    }else{//parent
       printf("parent glob %d\n", glob);
    }
    return 0;
}

运行结果:
这里写图片描述
释:子进程直接改变了父进程的变量值,因为子进程在父进程的地址空间中运行。

二、进程终止
1、进程退出的情况
(1)代码运行完毕,结果正确;
(2)代码运行完毕,结果错误;
(3)代码异常终止。

2、常见的进程退出方法
(1)正常终止
1)从主函数(main)返回

2)调用_exit函数

#include<unistd.h>
void _exit(int status);
参数:status定义了进程的终止状态,父进程通过wait来获取该值。
说明:虽然status是int,但是仅有低8位可以被父进程所利用,所有_exit(-1)时,在终端执行$?发现返回值是255

3)调用exit函数
A、exit函数应用格式:

#include<unistd.h>
void exit(int status);

B、调用exit前的工作
a、执行用户定义的atexit或on_exit清理函数。
b、关闭所有打开的流,所有的缓存数据均被写入。
c、调用_exit。

其过程如图所示:
这里写图片描述

d、return退出
return是一种更常见的退出进程方法。执行return等同于执行exit(n),因为调用main函数时会将main的返回值当做exit的参数。

(2)异常退出:
Ctrl+c:信号终止

三、回收子进程–进程等待
1、进程等待的必要性:
僵尸子进程即使不运行,也会消耗系统的内存资源。父进程可通过进程等待的方式回收子进程,获取子进程的退出信息,避免造成僵尸进程。

注:如果一个父进程终止了,内核会安排init进程成为它的孤儿进程的养父。init进程的PID为1,是在系统启动时内核创建的,它不会终止,是所有进程的祖先。一旦终止了,系统将关闭。

2、进程等待的方法:
(1)wait方法
工作格式:

#include<sys/types.h>
#include<sys/wait.h>

pid_t wait(int status);

释:
1)返回值:成功返回被等待的进程pid,失败返回-1。
2)参数:输出型参数,获取子进程退出状态,不关心则可以设置成为NULL。

(2)waitpid方法
工作格式:

pid_t waitpid(pid_t pid, int *statusp, int options);

返回值:
1)当正常返回的时候,waitpid返回收集到的子进程的进程id;
2)如果设置了选项WNOHANG,而调用时waitpid发现没有已退出的子进程可收集,则返回0;
3)如果调用中出错,则返回-1。这时errno会被设置成相应的值以指示错误所在。

参数:
1)判断等待集合的成员:pid
A、当pid=-1,等待集合由父进程的所有子进程组成,与wait等效。
B、当pid>0,等待集合由一个单独的子进程组成,它的进程ID等于pid。

2)检查已收回子进程的退出状态:status
如果statusp的参数是非空的,那么waitpid就会在status中放上关于导致返回的子进程的状态信息,status是statusp指向的值。wait.h头文件定义了解释status参数的几个宏:
A、WIFEXITED(status):若为正常终止子进程返回的状态,则为真。(查看进程是否正常退出)
B、WEXITSTATUS(status):若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)。

3)修改默认行为:options
WNOHANG:若pid指定的子进程没有结束,则waitpid函数返回0,不予以等待;若正常结束,则返回孩子进程ID。

4)注意:
A、如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回-1,还会设置errno为ECHILD,并且释放资源和获得子进程的退出信息。
B、如果在任意时刻调用wait/waitpid,子进程存在且正常进行,则进程可能阻塞。
C、如果waitpid函数被一个信号中断,那么它会返回-1,并设置errno为EINTR。

(3)获取子进程的状态(status)
wait/waitpid都有一个status参数,该参数是一个输出型参数,有操作系统填充。如果传递NULL,表示不关心子进程的退出状态信息;否则,操作系统会根据该参数将子进程的退出信息反馈给父进程。status不能简单的当作位图来看待,具体细节如下图所示(只研究status低16位比特位):
这里写图片描述
代码如下:
【例】

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<sys/wait.h>

int main()
{
    pid_t pid;
    if((pid=fork()) == -1)
       perror("fork"),exit(1);

    if(pid == 0){
        sleep(6);
        exit(3);
    }else{
        int st;
        int ret = wait(&st);

        if(ret > 0  && ( st & 0x7f ) == 0){//exit
            printf("child exit code:%d\n", (st>>8)&0xff);
        }else if(ret > 0){
            printf("sig code : %d\n", st&0x7f);
        }
    }
}

运行结果:

[hongji@localhost 11_20]$ ./a.out
child exit code:3
[hongji@localhost 11_20]$ 

3、具体代码实现
【例1】进程的阻塞等待方式

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<sys/wait.h>

int main()
{
    pid_t pid;
    pid = fork();
    if(pid < 0){
        printf("%s fork error\n", __FUNCTION__);
        return 1;
    }else if(pid == 0){//child
        printf("child is run, pid is : %d\n", getpid());
        sleep(6);
        exit(257);
    }else{
        int status = 0;
        pid_t ret = waitpid( -1, &status, 0);//block wait 5s
        printf("this is test for wait\n");
        if(WIFEXITED(status) && ret == pid){
            printf("wait child 5s success, child return code is :%d.\n", WEXITSTATUS(status));
        }else{
            printf("wait child failed, return.\n");
            return 1;
        }
    }
    return 0;
}

运行结果:
这里写图片描述

【例2】进程非阻塞方式
“`
1 #include

运行结果:
![这里写图片描述](http://img.blog.csdn.net/20171122124312799?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzgxMjE4NzQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

【例3】使用waitpid函数不按照特定的顺序回收僵死子进程
 1  #include<stdio.h>
 2  #include<stdlib.h>
 3  #include<unistd.h>
 4  #include<sys/wait.h>
 5  #include<errno.h>
 6  #define N 6
 7  
 8  int main()
 9  {
10      int i, status;
11      pid_t pid;
12  
13      //parent create N children
14      for(i = 0; i < N; i++)
15          if(fork() == 0)
16              exit(100+i);
17  
18      //parent reaps N children in no particular order
19      while((pid = waitpid(-1, &status, 0)) > 0){
20          if(WIFEXITED(status))
21              printf("child %d terminated normally\n", pid, WEXITSTATUS(status));
22          else
23              printf("child %d terminated abnormally\n", pid);
24      }
25  
26      //The only narmal terminated is if there are no more children
27      if(errno != ECHILD)
28          perror("waitpid error"),exit(1);
29  
30      exit(0);
31  }

运行结果:
![这里写图片描述](http://img.blog.csdn.net/20171122124411435?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzgxMjE4NzQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

【例4】使用waitpid按照创建子进程的顺序来回收这些僵死的子进程。
  ```
   1    #include<stdio.h>
     2  #include<stdlib.h>
     3  #include<unistd.h>
     4  #include<errno.h>
     5  #include<sys/wait.h>
     6  #define N 6
     7  
     8  int main()
     9  {
    10      int status, i;
    11      pid_t pid[N], retpid;
    12      
    13      //parent create N children
    14      for(i = 0; i < N; i++)
    15          if((pid[i] = fork()) == 0)
    16              exit(100+1);
    17  
    18      //parent reaps N children in order
    19      i = 0;
    20      while((retpid = waitpid(pid[i++], &status, 0)) > 0){
    21          if(WIFEXITED(status))
    22              printf("child %d terminated normally with exit status=%d\n", retpid, WEXITSTATUS(status));
    23          else
    24              printf("child %d terminated abnomally\n", retpid);
    25  }
    26  
    27      //the only normal termination is if there are no more children 
    28      if(errno != ECHILD)
    29          perror("waitpid error!\n"),exit(1);
    30  
    31      return 0;
    32  }

运行结果:
这里写图片描述

2019-07-11 08:27:50 qq_28245087 阅读数 41

          我们的知道进程是程序的实例,进程是程序向操作系统申请资源(如内存空间和文件句柄等)的基本单位。而线程是进程中可独立执行的最小单位,一个进程中可包含很多线程。而该进程中的所有线程共享着该进程申请的资源。进程就是正在执行的程序。而在Linux中,可以使用一个进程来创建另外一个进程。这样的话,Linux的进程的组织结构其实有点像Linux目录树,是个层次结构的,可以使用pstree命令来查看(如图1)。在最上面是init程序的执行进程。它是所有进程的老祖宗。Linux提供了两个函数来创建进程同,分别是fork()和execle();

     图1:

           

一、进程的七种状态

      (1)、R运行状态(runing):并不意味着进程一定在运行中,也可以在运行队列里;
      (2)、S睡眠状态(sleeping):进程在等待事件完成;(浅度睡眠,可以被唤醒);
      (3)、D磁盘睡眠状态(Disk sleep):不可中断睡眠(深度睡眠,不可以被唤醒,通常在磁盘写入时发生);
      (4)、T停止状态(stopped):可以通过发送SIGSTOP信号给进程来停止进程,可以发送SIGCONT信号让进程继续运行;
      (5)、X死亡状态(dead):该状态是返回状态,在任务列表中看不到;
      (6)、Z僵尸状态(zombie):子进程退出,父进程还在运行,但是父进程没有读到子进程的退出状态,子进程进入僵尸状态;
      (7)、t追踪停止状态(trancing stop);

       查看进程的状态命令:ps aux | grep pid | grep -v grep    

       如图:查询的是sshd进程的状态

           

    PS: 僵尸进程的危害  
        1 上面说到僵尸进程是由于父进程没有读取到子进程的退出信息而产生的,那么我们是不是就可以理解为父进程一直以为处于僵尸状态的子进程是没有退出的。而进程是需要维护的,僵尸进程就会一直需要PCB对其进行维护;
       2 浪费内存资源。如果僵尸进程一直没有退出,就会一直占用这块内存,就会导致内存资源的浪费;
       3 内存泄漏。僵尸进程一直占用资源,但是却不使用,就可能会导致内存泄漏。

二、进程的优先级

      分别为nice值和Priority值

      当我们使用top命令查询进程时,如图红色框中的值即是nice值和Priority

      

      1) nice值
             反应一个进程“优先级”状态的值
             取值范围是 -20 ~ 19, 40个级别
             nice值越小,“优先级”越高
     2)  Priority值
             优先级值
             linux上实现了140个优先级范围,取值是从0~139
             0 ~ 99表示实时进程;100 ~ 139表示非实时进程

三、进程操作的常用命令

      1、常用的进程动态查看命令ps

           1)、常用命令组合 ps aux ,该命令组合和ps -ef组合功能一样

                a:与终端有关的进程,用户通过终端启动,退出shell时,进程会终止。
                x:与终端无关的进程,系统启动过程中自动启动的进程。
                u:以用户为中心组织进程状态显示

              

    2、常用top命令

        1)、语法:top [options]

        2)、参数: 

                -d #:指定刷新时间间隔,默认5秒

     -n #:指定刷新批次,即指定刷新次数,刷新完成后自动退出

     -b:以批次方式显示

       3)、当使用top命令输出时,可以使用如下命令对输出结果进行操作

              a、排序相关
                    P:占CPU百分比%CPU排序
                    M:占内存百分比%MEM排序
                    T:累计占用CPU时间TIME+排序

               b、 开关相关
                    l:第一行uptime信息开关
                    t:第二行tasks和第三行cpu信息开关
                    m:第四行mem和第五行swap信息开关

        4)、top 查询结果前5行参数详细说明

            

            第 一行 分别显示:系统当前时间 系统运行时间 当前用户登陆数 系统负载。*系统负载(load average),这里有三个数值,分别   是系统最近1分钟,5分钟,15分钟的平均负载。一般对于单个处理器来说,负载在0 — 1.00 之间是正常的,超过1.00就要引起注意了。在多核处理器中,你的系统均值不应该高于处理器核心的总数。
           第二行 分别显示:total进程总数、 running正在运行的进程数、 sleeping睡眠的进程数、stopped停止的进程数、 zombie僵尸进程数。 
           第三行分别显示:
               %us 用户空间占用CPU百分比、
               %sy 内核空间占用CPU百分比、
               %ni 用户进程空间内改变过优先级的进程占用CPU百分比、
               %id 空闲CPU百分比、
               %wa 等待输入输出(I/O)的CPU时间百分比 、
               %hi指的是cpu处理硬件中断的时间、%si指的是cpu处理软中断的时间 、
               %st用于有虚拟cpu的情况,用来指示被虚拟机偷掉的cpu时间。
                通常id%值可以反映一个系统cpu的闲忙程度。
       第四行 MEM :total 物理内存总量、    used 使用的物理内存总量、free 空闲内存总量、    buffers 用作内核缓存的内存量。
       第五行 SWAP:total 交换区总量、     used 使用的交换区总量、free 空闲交换区总量、 cached 缓冲的交换区总量。
 
       PS:buffers和cached的区别需要说明一下,buffers指的是块设备的读写缓冲区,cached指的是文件系统本身的页面缓存。它们都是linux操作系统底层的机制,目的就是为了加速对磁盘的访问。

        5)、使用top命令得到的结果及列的参数说明

              

            红色框里的值对应代表意思如下:

           PID:进程号
           USER:进程属主
           PR:priority 的简写,进程优先级
           NI:nice的简写,与PR值联合控制进程的优先级
           VIRT:进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
           RES:进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA
           SHR:共享内存大小,单位kb
           S:进程状态。
           %CPU:CPU使用率。
           %MEM:内存使用率。
           TIME+:CPU使用时间累和,即进程一共占用CPU多久
           COMMAND:进程对应的命令

3)、pgrep命令

        常用参数:

               -o:仅显示找到的最小(起始)进程号; 
               -n:仅显示找到的最大(结束)进程号; 
               -l:显示进程名称; 
               -P:指定父进程号; 
               -g:指定进程组; 
               -t:指定开启进程的终端; 
               -u:指定进程的有效用户ID。

 4)、pstree命令

        pstree指令用ASCII字符显示树状结构,清楚地表达程序间的相互关系。如果不指定程序识别码或用户名称,则会把系统启动时的第一个程序视为基层,并显示之后的所有程序。若指定用户名称,便会以隶属该用户的第一个程序当作基层,然后显示该用户的所有程序。

     常用参数:

        -a  显示每个程序的完整指令,包含路径,参数或是常驻服务的标示。
   -c  不使用精简标示法。
   -G  使用VT100终端机的列绘图字符。
   -h  列出树状图时,特别标明现在执行的程序。
   -H<程序识别码>  此参数的效果和指定"-h"参数类似,但特别标明指定的程序。
   -l  采用长列格式显示树状图。
   -n  用程序识别码排序。预设是以程序名称来排序。
   -p  显示程序识别码。
   -u  显示用户名称。
   -U  使用UTF-8列绘图字符。
   -V  显示版本信息。

四、进程的停止

        kill命令的理解与运用

        作用:用来终止一个进程

       原理: kill命令的工作原理是,向Linux系统的内核发送一个系统操作信号和某个程序的进程标识号,然后系统内核就可以对进程标识号指定的进程进行操作比如在top命令中,我们看到系统运行许多进程,有时就需要使用kill中止某些进程来提高系统资源。

        我们可以使用kill -l命令查询出kill命令可选参数列表,如下图:

        

        下面是常用的信号及解释:

代号 名称 内容
1 SIGHUP 启动被终止的程序,可让该进程重新读取自己的配置文件,类似重新启动。
2 SIGINT 相当于用键盘输入 [ctrl]-c 来中断一个程序的进行。
9 SIGKILL  代表强制中断一个程序的进行,如果该程序进行到一半,那么尚未完成的部分可能会有“半产品”产生,类似 vim会有 .filename.swp 保留下来。
16 SIGTERM  以正常的方式来终止该程序。由于是正常的终止,所以后续的动作会将他完成。不过,如果该程序已经发生问题,就是无法使用正常的方法终止时,输入这个 signal 也是没有用的。
19 SIGSTOP 相当于用键盘输入 [ctrl]-z 来暂停一个程序的进行。  

  常用命令:       

       a、kill -15 pid

            这条命令发信号让进程正常退出。所谓的正常退出是指按应用程序自己的退出流程完成退出,这样就可以清理并释放资源。比如 vim 程序,如果是正常的退出,就会删除掉临时文件 *.swp。
既然信号 15 是退出进程的正确方式,那它也应该是最常用的方式,因而我们可以省略参数 -15。

        b、kill pid

             这条命令和上面的命令是等价的,kill 命令默认发送信号 15 给目标进程。
当进程出现了异常状况,不能通过信号15正常退出时,我们就需要通过非常的手段直接终结掉进程。所谓的非常手段就是传递信号 9 给目标进程!

        c、kill -9 pid

             这样结束掉的进程不会进行资源的清理工作,所以如果你用它来终结掉 vim 的进程,就会发现临时文件 *.swp 没有被删除。

        PS:使用信号 15 是安全的,而信号 9 则是处理异常进程的最后手段,请勿滥用。

 五、工作中常用的命令组合实例

      1、以树形结构查询一个进程的所有子进程命令: ps -p pid

      

    2、查询出某个服务的进程运行状态,包括cpu等相关信息,可使用ps aux | grep pid/服务名称  和ps ef | grep pid/服务名称   

   3、查询出系统中所有cpu使用情况: 使用top命令列出结果后,在按数字1展开cpu信息列表,还可以使用t键以不同的形式查看结果

      

4、如何正确的停步一个进程,我们可以使用 kill -15 ill -15 pid来正常停步。

5、在java项目中,我们如何使用java提供的工具来管理和查看进程执行情况呢。这里介绍一个名叫jstack的命令工具。

       a、命令jstack -l pid时可以查看进程中的线程运行情况,如图:

       

     b、也可以使用命令jstack pid > cpu0414.log 把结果生成文件下载下来阅读。

6、如何查询出一个进程的所有子进程,包括运行详细信息。我们可以使用命令top -p 26324 -H,结果如下:

     ​​​​​​​

            

 

 

 

#6.Linux的进程管理

阅读数 151

没有更多推荐了,返回首页