入职第三个月的第一天搞崩公司服务器 近期yolov5模型(参考github地址:https://github.com/ultralytics/yolov5)比较火,准备上手更新一下之前用v3做的项目,处理过数据格式问题后,python train.py --img-size 640 --batch-size 16 --epochs 300 --data ./data/score.yaml --cfg ./models/yolov5x.yaml --weights weights/yolov5x.pt准备运行训练代码,结果发生了内核死循环,进程杀不掉的问题,各种kill命令也不好使,最终只能reboot服务器解决问题。
python train.py --img-size 640 --batch-size 16 --epochs 300 --data ./data/score.yaml --cfg ./models/yolov5x.yaml --weights weights/yolov5x.pt开始训练后,服务器发生如下状况: 此时ctrl+c/ctrl+z都无法终止进程,本以为这是不打印训练过程,就放着进程跑了一天(晚上做梦还梦到第二天模型训练好了,我要开始写接口了),结果第二天还是处在上图所示的样子。 因为是screen -S sceesion_name进的screen,我就直接screen -S session_name -X quitkill掉这个进程,原以为结束了,结果才是问题的刚刚开始。 运行nvidia-smi发现事情并没有这么简单 有个PID=323125的进程占着八个GPU的内存,因为我当时训练的时候设置了多进程同时训练,大概率是我的进程没有被杀掉吧,ps -ef |grep 323135查看,的确是我起的进程: 可以看到kill掉screen并没有结束他运行的进程,理论上kill掉screen应该是结束掉screen上的所有进程包括父进程和子进程,但是这个地方的确进程还在,考虑应该是screen是父进程,训练是子进程,父进程强制杀掉以后,子进程托管到了0号进程,查了一些博客大部分在讲应该是进程变成了僵尸进程,按照博客上相关方法做了以下尝试:
step1 用ps和grep命令寻找僵尸进程:
ps -A -ostat,ppid,pid,cmd | grep -e '^[Zz]' #{-A 参数列出所有进程;-o 自定义输出字段 我们设定显示字段为 stat(状态), ppid(进程父id), pid(进程id),cmd(命令)这四个参数}的确发现了几个僵尸进程: 其中Z表示进程不活跃,在找解决方法的时候看到了一个对僵尸进程描述比较形象的博客,贴在这里(https://www.sohu.com/a/210923606_261288)所谓僵尸进程可以这样理解:
“你是一家建筑公司的老板。你每天根据工人们的工作量来支付工资。 有一个工人每天来到施工现场,就坐在那里, 你不用付钱, 他也不做任何工作。 他只是每天都来然后呆坐在那,仅此而已!”这个工人就是僵尸进程的一个活生生的例子。但是, 如果你有很多僵尸工人, 你的建设工地就会很拥堵从而让那些正常的工人难以工作。
step2 kill 进程 如上图所示:我程序中从第二行到最后一行的僵尸进程都是由PID=323135这个父进程产生的,一般僵尸进程的子进程很难kill掉,所以我们就kill他的父进程,键入kill -HUP 323135来杀掉父进程,父进程结束后,子进程变成孤儿进程,然后会被init进程清除
其实正常情况到这儿就结束了,但这却不是我的问题所在,当然,如果你遇到僵尸进程的问题上述的方法完全可以解决。
kill掉僵尸进程并没有解决内存占用问题,top一下,发现有运行中的程序在占用内存,同样是PID=323135的子进程,但他是run中的进程,这也就解决了我一开始的疑问(“为什么僵尸进程还占用这么大的内存”)。 那么,究竟是什么原因呢,调出来模型epoch的log以后发现每次起的模型都是在调用GPU的时候出现了问题,在此处陷入了内核死循环,此时kill命令并不是失效,而是kill命令也在等待,等待内核结束循环,但死循环永远不会结束,这也就导致了kill命令一直在等待,直观上表现出内核不接受kill命令的状态。这种问题有且只有一个解决方案。
reboot有人说:“你罗里吧嗦这么多,你直接告诉我重启不完了” 服务器上是多任务工作,重启需要协调同事,保证别人没有在服务器上跑程序,而且服务器上部署着一些接口,重启期间接口不能用影响正常网站工作。 最后,此文也是记录我为了解决一个小问题的探索,同时为遇到相同问题的你提供一个小小的帮助。