在bash脚本中执行后台命令(加&)时,需要执行wait命令回收后台子进程的资源,否则会内存泄露?
最近遇到一个奇特的问题,在脚本中反复调用后台命令(后台命令执行后会退出),发现一段时间后,内存占用明显增加,有内存泄露的迹象。
经过深入分析,得出结论:
在脚本中,调用后台执行的命令,确实应该wait,不wait的话,确有内存泄露的情况,不信可以自己写个死循环调用后台命令的脚本,很容易复现的。
也可以google搜一下脚本多任务,可以看到别人写的类似的脚本中,有很多都是用了wait的。
通过内存泄露检测,和bash相关代码和原理分析,问题产生的原因简单如下:
1、实际的内存泄露并不是被调用的后台进程自身产生的,泄露之处在于bash,bash调用后台命令,后台命令执行结束后,自身占用的资源(包括内存)应
该是成功回收的(bash中应该考虑了SIGCHLD信号的处理),但问题关键在于:bash自己会为每一个后台子进程创建一个数据结构,用于保存后台进
程的返回值,否则bash中就无法了解后台子进程的退出状态了,这在一些情况下,确实是需要了解的。所以,泄露的内存就在这个数据结构上,如果不用
wait,那么每个后台子进程对应的数据结构就无法回收。
2、理论上,泄露的数据结构应该很小,不会产生大的影响,但是另一个关键在于glibc的堆实现,如果死循环中不断的创建后台子进程,那就不断的会有相应
的数据结构分配,而其占用的内存很可能顶在了堆顶,我们知道,如果堆顶的内存不能回收,那么堆顶之下的内存也是不能回收的,所以由于该数据结构的泄露,可
能导致更大的内存泄露。经过分析故障当时bash进程的堆分布情况,确实可以确认这一点。
综上,这个问题由于bash和glibc和脚本用法共同导致。
所以,各位,如果后面要在bash中调用后台命令,建议都wait一下吧。。。。
示例脚本:
内存泄露的脚本:
-
#!/bin/bash
-
while true
-
do
-
date &
-
sleep 1
-
echo "$(ps -eo cmd,rss|grep -v grep|grep 't.sh')"
-
done
这个脚本运行后,可以明显看到内存有缓慢上升的情况。
内存不泄露的脚本:
-
#!/bin/bash
-
while true
-
do
-
date &
-
sleep 1
-
echo "$(ps -eo cmd,rss|grep -v grep|grep 't.sh')"
-
wait
-
done
而这个脚本调用了wait,长时间运行,也不会有内存上升的情况。
阅读(1643) | 评论(0) | 转发(0) |