操作系统之进程和线程(僵尸进程、孤儿进程、守护进程、Linux常见命令)

1. 僵尸进程
① 僵尸进程概述
什么是僵尸进程?
在Linux系统中,任何一个子进程在调用exit()函数结束运行后,内核会释放该进程的所有资源,包括占用的内存和打开的文件等。
同时,也会留下一个叫做僵尸进程(Zombie)的数据结构,Zombie中存储了该进程的进程号、退出码、退出状态、使用的CPU时间等信息。即僵尸进程是早已死亡的子进程,但在进程表中占了一个位置(slot)。
子进程还会向父进程发送SIGCHLD信号,父进程调用wait()或者waitpid()函数可以将僵尸进程释放(为它收尸)。
父进程在没有释放掉僵尸进程就提前结束了,僵尸进程则会由init进程接管。init进程(PID = 1)会作为它的父进程,为它收尸。
但是如果父进程是一个循环,不会结束,却又没有为SIGCHLD信号绑定处理函数,或者没有调用wait()/waitpid()函数为僵尸进程收尸,则该僵尸进程会一直在系统中存在。
僵尸进程的危害:
如果系统中存在很多僵尸进程,进程号会被它们一直占用。
这时,有限的进程号将会耗尽,使得系统无法创建新的进程。
② 如何杀死僵尸进程?
查看系统中是否存在僵尸进程
Linux中的top命令可以实时显式系统中各个进程的资源占用情况。因此,可以先通过top命令查看系统中是否存在僵尸进程。
输入top命令后的部分内容如下:其中zombie前面的数字表示当前系统中存在的僵尸进程数。

Tasks: 337 total,   1 running, 327 sleeping,   0 stopped,   9 zombie
Cpu(s):  0.0%us,  0.0%sy,  0.0%ni, 54.3%id, 45.7%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:     64417M total,    42611M used,    21806M free,    10924M buffers
Swap:    32764M total,      684M used,    32080M free,    28841M cached
 
  PID USER      PR  NI  VIRT  RES  SHR S   %CPU %MEM    TIME+  COMMAND                                                                                       
 9563 root      20   0  9040 1312  820 R      0  0.0   0:00.19 top                                                                                           
15216 root      20   0     0    0    0 S      0  0.0   5:45.61 kworker/22:1                                                                                  
    1 root      20   0 10528  724  692 S      0  0.0   2:47.29 init                                                                                          
    2 root      20   0     0    0    0 S      0  0.0   0:16.94 kthreadd                                                                                      
    3 root      20   0     0    0    0 S      0  0.0   9:13.20 ksoftirqd/0                                                                                   
    6 root      RT   0     0    0    0 S      0  0.0  94846:34 migration/0                                                                                                                                                              
  • 查看具体是哪些进程为僵尸进程
  1. 状态为Z,后面有defunct标记的进程就是僵尸进程。
  2. 可以通过ps -ef | grep defunct命令查看具体的僵尸进程。

**å ç²æ ·å¼**

上述命令返回的结果中,第三列就是该僵尸进程的父进程,可以通过kill -9 PPID杀死其父进程。之后,僵尸进程将由init进程接手,会被init进程释放。

③如何避免僵尸进程?
父进程收到SIGCHLD信号后,调用wait()或者waitpid()函数释放僵尸进程。但是,这样会导致父进程挂起。
如果父进程很忙,可以使用signal函数为SIGCHLD信号安装handler,handler中会调用wait函数回收僵尸进程。子进程结束后,父进程收到SIGCHLD信号后会执行handler。
父进程显式地表示自己对子进程的结束不感兴趣:
父进程如果不关心子进程什么时候结束,可以通过signal(SIGCLD, SIG_IGN)或者signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣。
子进程结束后,内核会释放僵尸进程,并不在给父进程发送信号。
fork两次:
父进程fork一个子进程,然后继续工作
子进程fork一个孙进程后退出,孙进程将由init进程接管;孙进程结束后,init进程会对其进程回收。
子进程的回收还是需要父进程自己去完成
2. 孤儿进程(orphan)
孤儿进程:
父进程退出,而它的一个或多个子进程还在运行,这些子进程将成为孤儿进程(orphan process)。
估计进程将会被init进程收养,并由init进程完成对它们的状态收集工作。
由于孤儿进程会被init进程收养,因此孤儿进程调用exit()结束运行时,也会由init进程完成回收工作,而不会对系统造成危害。
孤儿进程与僵尸进程的区别:
孤儿进程: 子进程未运行结束,父进程却提前结束,这时子进程将会成为孤儿进程被init进程收养。init进程会完成对孤儿进程的回收工作,孤儿进程对系统没有危害。
僵尸进程: 子进程运行结束,父进程没有为SIGCHLD信号设置处理函数,或者调用wait()/waitpid()函数对其进程回收,成为系统中的僵尸进程。僵尸进程会占用系统中有限的进程号,导致系统无法创建新进程。因此,僵尸进程对系统有危害
3. 守护进程(Daemon)
① 什么是守护进程?
Linux Daemon(守护进程)是运行在后台的一种特殊进程,独立于控制终端,并且周期性的执行某种任务或者等待处理某些发生的事件。
守护进程不需要用户输入就能运行,它可以提供某种服务。并且不是对系统提供服务,就是对某个应用程序提供服务。
Linux中大多数的服务器就是通过守护进程实现,如系统日志进程syslogd、数据库服务器mysqld、web服务器httpd等。
守护进程一般在系统启动时就开启了,除非强制终止,否则直到系统关机都保持运行。
因为需要使用特殊端口1~1024访问某些特殊的资源,守护进程经常以超级用户(root)权限运行。
守护进程的父进程是init进程: 创建守护进程时,父进程在fork出子进程后就提前结束运行了。守护进程将会变成孤儿进程,由init进程收养。
守护进程是非交互式程序,没有控制终端,无论是标准输出设备stdout还是标准出错设备stderr的输出都需要进行特殊处理。
守护进程的名称通常以d结尾,如sshd、xinetd、crond等。
② 如何创建守护进程?
父进程fork()出子进程,然后提前调用exit()结束运行。
在子进程中调用setsid()函数创建新的会话。
再次fork出一个子进程并让父进程退出。
在子进程中调用chdir()函数,让根目录成为子进程的工作目录。
在子进程中调用unmask()函数,设置进程的文件权限码为0。
在子进程中关闭任何不需要的文件描述符。
4. Linux中的常见命令
用于文件操作的常见命令:cp(拷贝)、rm(删除)、mkdir(创建)、cd(切换目录)、mv(改名)、ls(罗列文件/文件夹)、tar(解压缩)、chmod(更改权限)、chown(更改所有者)
用于系统进程操作的常见命令:top/htop(查看系统中所有进程实时运行情况)、ps(列出系统中的进程)、lsof(查看某个端口是否被占用)、kill(杀死某个进程)、iotop(监控磁盘I/O情况)、ifconfig(查看本机IP)
5. 进程和线程的常见问题总结
1. 进程的状态转换?

五种或者带换出的六种
2. 进程和线程的区别?

总体区别: 进程是资源分配的基本单位,线程是CPU调度的基本单位(用工厂车间和生产线去讲解)
细分区别: 资源、调度、开销(创建和销毁的开销、上下文切换的开销)、通信方式
Linux中: Linux中内核调度的基本单位task_struct,内核线程和用户线程
3. 进程间的通信方式

管道(半双工、要求亲缘关系)
FIFO(半双工、不要求亲缘关系)
信号量(PV操作、互斥量,生产者-消费者问题)
信号
消息队列(无须考虑同步、有选择的接收消息)
共享内存(减少进程间的数据拷贝)
socket(不同机器间的进程通信)
4. 进程同步中的临界区有什么处理方法?

使用互斥量Mutex或synchronized关键字
5. 僵尸进程如何检测?

基础: top命令查看是否存在僵尸进程,ps -ef | grep defunct查看僵尸进程具体信息
进阶: kill命令杀死其父进程
高阶: 僵尸进程的形成、危害、如何避免
5. 线程启动的方法

创建的方法: 继承Thread类、重写Runnable接口、重写Callable接口
启动的方法: 只有start()
6. Linux进程管理的相关命令

top/htop命令、ps命令、lsof命令、kill命令
7. Java中哪些地方会发生OOM?一个进程有3个线程,如果一个线程抛出OOM,其他两个线程还能运行么?

JVM栈和本地方法栈动态扩展扩展时无法申请到足够的内存,会抛出OutOfMemoryException异常。
堆和方法区无法满足内存分配需求时,会抛出OutOfMemoryException异常。
一个线程OOM,其他线程仍然可以运行;主线程OOM,其他线程仍然可以运行。
8. Java进程挂掉,Linux下如何处理?

Java程序自身问题导致OOM?
JVM或JDK自身的bug导致crash?
查看系统日志是否被Linux的OOM-killer杀掉,查看是Java程序内存占用过大,还是有其他进程占用了大量内存?
9. 进程和线程那个快?线程之间的通信?

线程更快:创建和销毁、上下文切换都是线程快
线程之间通过共享数据进行通信。
————————————————
版权声明:本文为CSDN博主「晓之木初」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u014454538/article/details/99611816

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值