Linux进程详解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux进程详解相关的知识,希望对你有一定的参考价值。

参考技术A

ps是Linux 中最基础的浏览系统中的进程的命令。能列出系统中运行的进程,包括进程号、命令、CPU使用量、内存使用量等。接下来解读一下Linux操作系统的进程和Windows「Ctrl+Alt+delete」直接的差异。

在进行了解进程命令之前需要知道进程的一些状态

ps工具标识进程的5种状态码:

Linux操作系统进程执行的状态转换图如图所示:

下面来看一下 ps命令
ps --help命令可以查看ps命令的使用说明

或者使用 man ps命令 查询ps的详细说明

在 man手册 关于ps的解读中,总结了一下几个参数的含义:

以上的参数是可以拼接使用的,那就了解一些常用的参数组合
ps aux命令

ps -ef命令

查看进程状态这两个是命令是最常用的,使用 ps aux 可以查看进程的详细运行状态等。使用 ps -ef 不仅可以显示自身的PID,也可以显示PPID(父进程)。但是显示不了进程的运行状态

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

man手册关于top的解释

关闭进程,重启进程
在上一片文章中 linux的目录结构 里面说过,在目录/etc/init.d/目录下包含许多系统各种服务的启动和停止脚本。假设进程占用内存较大或者进程异常,我们是重启这个进程restart。如下图所示:

我们重启了mysqld这个进程,可以看出进程号已经改变(从15743到15964),说明进程已经重启。

Linux下有3个特殊的进程,idle进程(PID=0), init进程(PID=1)和kthreadd(PID=2)

我们来看一下进程状态[下面是删减版,进程数量太多,列举一部分]

可以看到很多进程的PPID号是1和2。也就是init进程和kthreadd进程。

在使用Windows系统的过程中,都碰到过应用程序卡死的情况。应对此问题,我们一般都是等待失去响应的程序恢复,或者是直接使用任务管理器将其强制关闭,然后再重新打开。

在Linux中,遇到特别耗费资源的进程,当然需要使用 top命令 查看进程占用率高的进程。或者使用 free -m命令 查看内存剩余。假设需要强杀进程来释放空间。我们涉及到Linux中信号📶的知识,在这里简单的描述一下,信号的详解会在接下来的文章里面叙述。
free -m命令查看内存空间

在linux中存在着64种信号
使用 kill -l命令 查看信号列表

在前面说过进程会被这些个信号> (进程收到SIGSTOP, SIGSTP, SIGTIN, SIGTOU信号强制停止运行) 那问题就在于如何发信号给这些个进程。
使用kill命令发信号

我们从上面可以看到 mysqld进程被重启了 。

关于Linux的这一块进程的知识还有很多,后面的文章跟大家分享僵尸进程,孤儿进程等等知识,以及守护进程(daemon进程).

Linux僵尸进程详解

僵尸进程概念

在 unix/linux 中,正常情况下,子进程是通过父进程创建的。子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程到底什么时候结束。当一个进程完成它的工作终止之后,它的父进程需要调用 wait()
或者 waitpid()系统调用取得子进程的终止状态。

僵尸进程:一个进程使用 fork 创建子进程,如果子进程退出,而父进程并没有调用 wait 或 waitpid 获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死(zombie)进程。

僵尸进程问题及危害

unix提供了一种机制可以保证只要父进程想知道子进程结束时的状态信息,就可以得到。

这种机制就是: 在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。

但是仍然为其保留一定的信息(包括进程号 the process ID,退出状态 the termination status of the process,运行时间 the amount of CPU time taken by the process 等)。直到父进程通过 wait / waitpid 来取时才释放。

但这样就导致了问题,如果进程不调用 wait / waitpid 的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。

实现一个僵尸进程

详细内容请移驾另一篇博客:
https://yangyongli.blog.csdn.net/article/details/118738169

僵尸进程处理

我们知道僵尸进程是不能通过 kill 命令来终止的,想要处理系统中的僵尸进程,只能找到产生僵尸进程的父进程,使用 kill 命令终止父进程即可。此时僵尸进程成为孤儿进程,会被 init 进程接管,调用 wait 函数释放资源。

僵尸进程的预防

(1)通过信号机制

子进程退出时向父进程发送 SIGCHILD 信号,父进程处理 SIGCHILD 信号。
在信号处理函数中调用 wait 进行处理僵尸进程。测试程序如下所示

通过信号量及时发现了僵尸进程并处理了。
在这里插入图片描述

/*************************************************************************
    > File Name: main.c
    > Author: 杨永利
    > Mail: 1795018360@qq.com 
    > Created Time: 2021年07月14日 星期三 21时54分29秒
 ************************************************************************/

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>

static void sig_child(int signo);

int main()
{
	pid_t pid;
	//创建捕捉子进程退出信号
	signal(SIGCHLD, sig_child);
	pid = fork();
	if (pid < 0)
	{
		perror("fork error:");
		exit(1);
	}
	else if (pid == 0)
	{
		printf("I am child process,pid id %d.I am exiting.\\n",getpid());
			exit(0);
	}
	printf("I am father process.I will sleep two seconds\\n");
	//等待子进程先退出
	sleep(2);
	//输出进程信息
	system("ps -o pid,ppid,state,tty,command");
	printf("father process is exiting.\\n");
	return 0;
}

static void sig_child(int signo)
{
	pid_t pid;
	int stat;

	//处理僵尸进程
	while ((pid = waitpid(-1, &stat, WNOHANG)) > 0)
		printf("child %d terminated.\\n", pid);
}

(2)Fork 两次

《Unix 环境高级编程》8.6 节说的非常详细。原理是将子进程成为孤儿进程,从而其的父进程变为 init 进程,通过 init 进程可以处理僵尸进程。测试程序如下所示:

在这里插入图片描述

/*************************************************************************
    > File Name: main.c
    > Author: 杨永利
    > Mail: 1795018360@qq.com 
    > Created Time: 2021年07月14日 星期三 22时08分39秒
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main()
{
	pid_t pid;
	//创建第一个子进程
	pid = fork();
	if (pid < 0)
	{
		perror("fork error:");
		exit(1);
	}
	//第一个子进程
	else if (pid == 0)
	{
		//子进程再创建子进程
		printf("I am the first child process.pid:%d\\tppid:%d\\n", getpid(), getppid());
		pid = fork();
		if (pid < 0)
		{
			perror("fork error:");
			exit(1);
		}
		//第一个子进程退出
		else if (pid > 0)
		{
			printf("first procee is exited.\\n");
			exit(0);
		}
		//第二个子进程
		//睡眠 3s 保证第一个子进程退出,这样第二个子进程的父亲就是 init 进程里
		sleep(3);
		printf("I am the second child process.pid: %d\\tppid:%d\\n", getpid(), getppid());
		exit(0);
	}
	//父进程处理第一个子进程退出
	if (waitpid(pid, NULL, 0) != pid)
	{
		perror("waitepid error:");
		exit(1);
	}
	exit(0);
	return 0;
}

以上是关于Linux进程详解的主要内容,如果未能解决你的问题,请参考以下文章

Linux守护进程详解

Linux僵尸进程详解

Linux僵尸进程详解

[OS-Linux]详解Linux的进程1(进程概念PCB进程创建,进程状态,僵尸进程,孤儿进程)

[OS-Linux]详解Linux的进程1(进程概念PCB进程创建,进程状态,僵尸进程,孤儿进程)

Linux 中僵尸进程详解