模拟程序
#include <stdio.h> #include <unistd.h> //本程序启动一个子进程,父子进程无限循环不退出 //编译:gcc create_zombie.c -o zombie //执行:./zombie //使用方法 //kill父进程,则子进程变为孤儿进程,可以kill子进程解决 //kill子进程,则子进程变为僵尸进程,可以kill父进程解决 int main() { //fork一个进程,作为子进程 printf("fork a child process\n"); pid_t pid = fork(); if (pid > 0) { //父进程 printf("---i am parent: %d\n", getpid()); } else if (pid == 0) { //子进程 printf("---i am child: %d\n", getpid()); } //死循环,避免进程退出,方便人为操作模拟孤儿进程与僵尸进程 while(1) { sleep(1); } return 0; }
僵尸进程
处于僵死状态的进程危害:会造成资源泄漏
僵尸进程的产生原因:子进程先于父进程退出,因为要保留退出原因,因此操作系统不能直接释放所有资源,通知父进程获取退出原因,允许操作系统释放资源,但是父进程没有关注这个通知导致子进程退出后无法释放所有资源,处于僵死状态成为僵尸进程
如何处理:结束掉父进程,僵尸进程也就结束了
如何识别:进程状态为 Z+,可以通过 top 命令(确认僵尸进程数量)以及 ps 命令(确认进程状态)
[root@localhost ~]# top top - 14:20:31 up 20:31, 2 users, load average: 0.31, 0.40, 0.46 Tasks: 111 total, 1 running, 109 sleeping, 0 stopped, 1 zombie [root@localhost ~]# ps -A -ostat,ppid,pid,cmd | grep -e '^[Zz]' Z+ 6720 6721 [zombie] <defunct>
孤儿进程
处于孤儿状态的进程危害:除程序自身业务完整性外,一般来说,孤儿进程并不会有什么危害
孤儿进程的产生原因:父进程先于子进程退出,子进程就会成为孤儿进程,运行在后台,父进程成为1号进程(init初始化进程)
如何处理:结束掉子进程即可
如何识别:进程状态转为后台,即状态没有+号,父进程ID变为 1,可以通过 ps 命令(确认进程状态)
[root@localhost ~]# ps -A -ostat,ppid,pid,cmd | grep zombie S+ 6858 6928 ./zombie S+ 6928 6929 ./zombie [root@localhost ~]# kill -9 6928 [root@localhost ~]# ps -A -ostat,ppid,pid,cmd | grep zombie S 1 6929 ./zombie
附录:Linux进程状态
D 不可中断睡眠 (通常是在IO操作) 收到信号不唤醒和不可运行, 进程必须等待直到有中断发生 R 正在运行或可运行(在运行队列排队中) S 可中断睡眠 (休眠中, 受阻, 在等待某个条件的形成或接受到信号) T 已停止的 进程收到SIGSTOP, SIGSTP, SIGTIN, SIGTOU信号后停止运行 W 正在换页(2.6.内核之前有效) X 死进程 (未开启) Z 僵尸进程 进程已终止, 但进程描述符存在, 直到父进程调用wait4()系统调用后释放BSD风格的 < 高优先级(not nice to other users) N 低优先级(nice to other users) L 页面锁定在内存(实时和定制的IO) s 一个信息头 l 多线程(使用 CLONE_THREAD,像NPTL的pthreads的那样) + 在前台进程组