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

1. 僵尸进程
① 僵尸进程概述
  • 什么是僵尸进程?
  1. 在Linux系统中,任何一个子进程在调用exit()函数结束运行后,内核会释放该进程的所有资源,包括占用的内存和打开的文件等。
  2. 同时,也会留下一个叫做僵尸进程Zombie)的数据结构,Zombie中存储了该进程的进程号退出码退出状态使用的CPU时间等信息。即僵尸进程是早已死亡的子进程,但在进程表中占了一个位置(slot)
  3. 子进程还会向父进程发送SIGCHLD信号,父进程调用wait()或者waitpid()函数可以将僵尸进程释放(为它收尸)。
  4. 父进程在没有释放掉僵尸进程就提前结束了,僵尸进程则会由init进程接管init进程(PID = 1)会作为它的父进程,为它收尸。
  5. 但是如果父进程是一个循环,不会结束,却又没有为SIGCHLD信号绑定处理函数,或者没有调用wait()/waitpid()函数为僵尸进程收尸,则该僵尸进程会一直在系统中存在。
  • 僵尸进程的危害:
  1. 如果系统中存在很多僵尸进程,进程号会被它们一直占用。
  2. 这时,有限的进程号将会耗尽,使得系统无法创建新的进程
② 如何杀死僵尸进程?
  • 查看系统中是否存在僵尸进程
  1. Linux中的top命令可以实时显式系统中各个进程的资源占用情况。因此,可以先通过top命令查看系统中是否存在僵尸进程。
  2. 输入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命令查看具体的僵尸进程。
    **加粗样式**
  3. 上述命令返回的结果中,第三列就是该僵尸进程的父进程,可以通过kill -9 PPID杀死其父进程。之后,僵尸进程将由init进程接手,会被init进程释放。
③ 如何避免僵尸进程?
  • 父进程收到SIGCHLD信号后,调用wait()或者waitpid()函数释放僵尸进程。但是,这样会导致父进程挂起
  • 如果父进程很忙,可以使用signal函数为SIGCHLD信号安装handler,handler中会调用wait函数回收僵尸进程。子进程结束后,父进程收到SIGCHLD信号后会执行handler。
  • 父进程显式地表示自己对子进程的结束不感兴趣:
  1. 父进程如果不关心子进程什么时候结束,可以通过signal(SIGCLD, SIG_IGN)或者signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣。
  2. 子进程结束后,内核会释放僵尸进程,并不在给父进程发送信号。
  • fokr两次:
  1. 父进程fork一个子进程,然后继续工作
  2. 子进程fork一个孙进程后退出,孙进程将由init进程接管;孙进程结束后,init进程会对其进程回收。
  3. 子进程的回收还是需要父进程自己去完成
2. 孤儿进程(orphan)
  • 孤儿进程:
  1. 父进程退出,而它的一个或多个子进程还在运行,这些子进程将成为孤儿进程(orphan process)。
  2. 估计进程将会被init进程收养,并由init进程完成对它们的状态收集工作
  • 由于孤儿进程会被init进程收养,因此孤儿进程调用exit()结束运行时,也会由init进程完成回收工作,而不会对系统造成危害
  • 孤儿进程与僵尸进程的区别:
  1. 孤儿进程: 子进程未运行结束,父进程却提前计数,这时子进程将会成为孤儿进程被init进程收养。init进程会完成对孤儿进程的回收工作,孤儿进程对系统没有危害
  2. 僵尸进程: 子进程运行结束,父进程没有为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. 进程同步中的临界区有什么处理方法?

  • 使用互斥量Mutexsynchronized关键字

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下如何处理?

  1. Java程序自身问题导致OOM?
  2. JVM或JDK自身的bug导致crash?
  3. 查看系统日志是否被Linux的OOM-killer杀掉,查看是Java程序内存占用过大,还是有其他进程占用了大量内存?

9. 进程和线程那个快?线程之间的通信?

  • 线程更快:创建和销毁、上下文切换都是线程快
  • 线程之间通过共享数据进行通信。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值