My Practical Experience On Linux
Linux 内核相关
僵尸进程
原因
- 父进程没有回收子进程的资源
- 子进程的进程描述符仍然存在,因此子进程成为僵尸进程
解决方法
- 父进程调用
wait()
函数,回收子进程的资源 - 或者父进程调用
waitpid()
函数,回收子进程的资源 - 或者父进程调用
signal(SIGCHLD,SIG_IGN)
函数,忽略SIGCHLD
信号,让内核自动回收子进程的资源
实际开发
当我们在 Linux 主机上遇到占用显存但是找不到对应的进程时(如下图案例所示),往往就是子进程所占用的资源没有被回收,而父进程已经结束。这种情况一般会在多线程并行当中出现,比如在多线程并行训练模型时,如果主线程在子线程结束之前就已经结束,那么子线程就会变成僵尸进程,占用显存。


对应的解决方法,一般可以通过检测僵尸进程,然后再寻找僵尸进程对应的父进程,安全地终止父进程后,操作系统就会自动清理对应的子进程。
- 检测僵尸进程在 ps aux 的输出中,僵尸进程(Zombie process)通常会在 STAT(进程状态)列标记为 Z,表示进程已经终止但仍然存在于进程表中,因为其父进程尚未回收它的退出状态。
1
ps aux | grep Z
ps aux
- ps 命令用于显示当前系统的进程信息,而 aux 选项的作用是:
- a:显示所有用户的进程(不仅仅是当前用户的)。
- u:以用户友好的格式(包括用户名、CPU 和内存使用等)显示进程信息。
- x:显示没有终端控制的进程(例如守护进程)。
运行ps aux
会输出系统中所有正在运行的进程的详细信息。
| grep Z
- |(管道):将 ps aux 命令的输出传递给 grep 进行筛选。
- grep Z:在 ps aux 的输出中查找包含字母 “Z” 的行。
- 查找僵尸进程对应的父进程可以通过以上命令,查找僵尸进程对应的父进程的
1
ps -o ppid= -p 2721429
PID
,然后进行终止. - 终止父进程当父进程被杀死后,操作系统会自动将这些僵尸进程的父进程设置为
1
kill -9 2721429
init
进程(PID 1
),相当于讲这些僵尸进程转移给了init
进程作为接管的父进程。init
是系统的主进程,它会自动调用wait()
来回收所有孤立的僵尸进程,从而清除它们。
nohup 后台运行
原理
nohup
是 no hang up
的缩写,它的作用是让进程在后台运行,即使终端关闭也不会影响进程的运行。
使用方法
1 | nohup command > output.log 2>&1 & |
其中,command
是要执行的命令,output.log
是输出日志文件,2>&1
表示将标准错误输出重定向到标准输出,&
表示将命令放到后台运行。
实际开发
1 | nohup sh test.sh > output.log 2>&1 & |
以上一条命令,基本能够解决大多数情况下的后台运行。
My Practical Experience On Linux