简介
僵尸进程(zombie process)是指一个已经终止但仍然在进程表中保留条目的进程。正常情况下,当一个进程完成执行并退出时,操作系统会通过父进程调用的wait()或waitpid()系统调用来收集该子进程的退出状态。如果父进程未及时调用这些函数,子进程的状态信息就无法从内核中移除,导致进程在内核中以“僵尸”状态存在。此状态下的子进程,使用kill -9 就是“鞭尸”,是无法移除僵尸进程的
僵尸进程的主要特点是它们不再消耗CPU或内存资源,因为其已终止,只保留一个进程号(PID)和少量的状态信息。然而,过多的僵尸进程会使系统的进程号资源耗尽,阻止新进程的创建,影响系统稳定性。
产生僵尸进程的常见原因包括:父进程未能及时俘获到子进程得退出信息,并对其进程信息进行处理,导致子进程进入、“僵尸状态”。本文以postgres 进行举例
“t” 状态解决办法
使用gdb挂住postgres(主进程),此时数据库得主进程处于t状态。将子进程kill 掉此时,子进程就会变成僵尸状态。
此状态下现存的客户端进程会一直保持写入状态。Wal文件持续增长中。此时主进程状态处于t状态。
ps -o pid,ppid,cmd,state,etime -p 1797
t状态表示进程被跟踪并停止(Traced and stopped)
使用ps -ef |grep 1797查看调用postgres(主进程的程序)的进程 ,将其kill 掉,postgresql运行会恢复正常。子进程会被重新拉起。此时主进程状态会恢复到S状态。
“T” 状态解决办法
“T”状态 表示进程被停止。
使用kill -19 1797 stop掉主进程,然后kill -9杀掉所有的子进程。模拟僵尸僵尸状态
此时父进程状态为T 状态,kill -19 之后,父进程将无法再处理子进程的退出消息。此时对父进程发送继续进程的指令kill -18 ,此时父进程会重新运行,并进行处理消息列表的信号。
“Z” 僵尸状态
进程已经终止,但父进程尚未回收它的退出状态,导致该进程变成僵尸进程。
,当然在以上的两个状态中,子进程也是处于“Z”状态,但是我们可以通过父进程进行判断僵尸进程的原因,使用危害较小的方式进行处理,如果此时的父进程state处于正常状态,但是子进程处于“Z”状态,此时引发原因就变得难以追踪。
模拟父进程没通过wait(),waipid()进行处理子进程退出信息,引发僵尸进程
编辑脚本zombie_process.py
使用一下指令进行调用
python3 zombie_process.py
脚本内容如下:
import os
import time
def create_zombie():
pid = os.fork() # 创建子进程
if pid > 0:
# 父进程:故意不处理子进程的退出状态
print(f"父进程 PID: {os.getpid()}")
print(f"子进程 PID: {pid}")
print("子进程变为僵尸进程(父进程不回收子进程)。")
time.sleep(60) # 父进程休眠,保持子进程为僵尸进程
elif pid == 0:
# 子进程
print(f"子进程 PID: {os.getpid()} 终止")
os._exit(0) # 子进程结束
if __name__ == "__main__":
create_zombie()
此时子进程处于“Z”状态,但是父进程确实正常state 状态,此时需要。kill父进程,让其由systemd一号进程进行接管,编处理僵尸进程的退出状况。