我和队友讨论过锁定.NET.他是一个非常聪明的人,在低级和高级编程方面拥有广泛的背景,但他在低级编程方面的经验远远超过我的.无论如何,他认为,如果可能的话,应该避免在预期会处于重负载的关键系统上进行.NET锁定,以避免"僵尸线程"崩溃系统的可能性很小.我经常使用锁定而且我不知道什么是"僵尸线程",所以我问道.我从他的解释中得到的印象是僵尸线程是一个已经终止但仍然保留在某些资源上的线程.他给出了僵尸线程如何破坏系统的一个例子是一个线程在锁定某个对象后开始一些程序,然后在某个时刻终止锁定才能被释放.这种情况有可能使系统崩溃,因为最终,尝试执行该方法将导致所有线程都在等待访问永远不会返回的对象,因为使用锁定对象的线程已经死亡.
我想我得到了这个的要点,但如果我离开基地,请告诉我.这个概念对我来说很有意义.我并不完全相信这是一个可能在.NET中发生的真实场景.我以前从未听说过"僵尸",但我确实认识到,在较低级别深入工作的程序员往往对计算基础(如线程)有更深入的了解.我肯定看到了锁定的价值,然而,我看到许多世界级程序员利用锁定.我也很有能力为自己评估这个,因为我知道这lock(obj)句话实际上只是语法糖:
bool lockWasTaken = false;
var temp = obj;
try { Monitor.Enter(temp, ref lockWasTaken); { body } }
finally { if (lockWasTaken) Monitor.Exit(temp); }
Run Code Online (Sandbox Code Playgroud)
因为Monitor.Enter并且Monitor.Exit被标记了extern.似乎可以想象.NET会做某种处理来保护线程免受可能产生这种影响的系统组件的影响,但这纯粹是推测性的,可能只是基于我从未听说过"僵尸线程"的事实.之前.所以,我希望我能在这里得到一些反馈:
两年多前我问过这个问题.今天发生这种事:
我在前台启动了我的程序(一个守护程序),然后我用它杀了它kill -9,但我得到了一个僵尸,我无法杀死它kill -9.如何杀死僵尸进程?
如果僵尸是一个死的进程(已经被杀死),我如何从输出中删除它ps aux?
root@OpenWrt:~# anyprogramd &
root@OpenWrt:~# ps aux | grep anyprogram
1163 root 2552 S anyprogramd
1167 root 2552 S anyprogramd
1169 root 2552 S anyprogramd
1170 root 2552 S anyprogramd
10101 root 944 S grep anyprogram
root@OpenWrt:~# pidof anyprogramd
1170 1169 1167 1163
root@OpenWrt:~# kill -9 1170 1169 1167 1163
root@OpenWrt:~# ps aux |grep anyprogram
1163 root 0 Z [cwmpd]
root@OpenWrt:~# kill -9 1163
root@OpenWrt:~# ps aux |grep anyprogram
1163 …Run Code Online (Sandbox Code Playgroud) 有没有办法确保所有创建的子进程在Python程序的退出时间都死了?通过子进程,我指的是使用subprocess.Popen()创建的.
如果没有,我应该迭代所有发出的杀戮然后杀死-9?什么更干净?
当父进程在子进程死后读取其退出状态时不使用等待系统调用时,会创建一个Zombie,并且当原始父进程在子进程终止时,孤立是由init回收的子进程.
在内存管理和进程表方面,这些进程的处理方式有何不同,特别是在UNIX中?
当僵尸或孤儿的创建可能对更大的应用程序或系统有害时,有什么例子或极端情况?
我的系统上有一个已解散的进程:
abc 22093 19508 0 23:29 pts/4 00:00:00 grep ProcA
abc 31756 1 0 Dec08 ? 00:00:00 [ProcA_my_collect] <defunct>
Run Code Online (Sandbox Code Playgroud)
如何在不重启机器的情况下终止上述过程?我试过了
kill -9 31756
sudo kill -9 31756
Run Code Online (Sandbox Code Playgroud) 我可以找到关于僵尸的问题,但没有一个直接解决它们是什么以及为什么以及它们如何发生.有几个解决了在回答特定问题但不解决原因的背景下僵尸进程的问题.
还有关于僵尸进程和有关Objective-C/Cocoa相关僵尸对象的问题的问题.有什么区别或这些有何关系?Mac/iPhone上的"EXEC_BAD_ACCESS"(或其他平台上的类似错误)是僵尸的代名词吗?
如何防止僵尸,是否有任何有助于避免僵尸的最佳做法?
将这些信息放在一个地方会很有帮助.如果可能,此问题旨在与平台/语言无关.
上下文就是这个Redis问题.我们有一个wait3()等待AOF重写子项在磁盘上创建新AOF版本的调用.当孩子完成后,通知父母wait3()以便用新的AOF替换旧的AOF.
但是,在上述问题的上下文中,用户向我们通知了一个错误.我修改了一点Redis 3.0的实现,以便在wait3()返回-1 时清楚地记录,而不是因为这种意外情况而崩溃.所以这就是显而易见的事情:
wait3() 当有待等待的孩子时,我们会打电话.SIGCHLD应设置为SIG_DFL,没有代码Redis的所有设置这个信号,所以它的默认行为.wait3()按预期成功运行.wait3()开始返回-1.AFAIK在我们调用的当前代码中wait3()是不可能的,因为当没有挂起的子节点时,因为当创建AOF子节点时,我们设置server.aof_child_pid为pid的值,并且我们仅在成功wait3()调用之后重置它.
所以wait3()应该没有理由失败-1 ECHILD,但它确实如此,所以可能僵尸孩子不是出于某种意想不到的原因而创建的.
假设1:在某些奇怪的条件下Linux可能会丢弃僵尸孩子,例如因为内存压力?看起来不合理,因为僵尸只附加了元数据但谁知道.
请注意,我们打电话wait3()给WNOHANG.并且鉴于默认情况下SIGCHLD设置为SIG_DFL,唯一应该导致失败并返回-1的条件,并且ECHLD应该没有可用于报告信息的僵尸.
假设2:可能发生的其他事情但是没有解释,如果它发生,是在第一个孩子死后,SIGCHLD处理程序被设置为SIG_IGN,导致wait3()返回-1和ECHLD.
假设3:有没有办法从外部移除僵尸儿童?也许这个用户有某种脚本可以在后台删除僵尸进程,以便信息不再可用wait3()?据我所知,如果父母不等待它(使用或处理信号)并且如果没有被忽略,则永远不可能移除僵尸,但也许有一些特定于Linux的方式.waitpidSIGCHLD
假设4:实际上有在Redis的代码一些bug,使我们成功wait3()的孩子第一次不正确复位状态,后来我们叫wait3()连连,但不再有僵尸,所以它返回-1.分析代码看起来不可能,但也许我错了.
另一件重要的事情:我们过去从未见过这一点.这显然只发生在这个特定的Linux系统中.
更新:Yossi Gottlieb提出 …
在iOS应用程序上使用Xcode几天后,我注意到有超过100个僵尸进程闲逛.似乎每次运行单元测试都有一个,每次我在模拟器中运行完整的应用程序时可能有一个.这是一个示例(清理和截断):
> ps -efj | grep $PRODUCT_NAME
502 2794 236 0 Wed12AM ?? 0:00.00 (MyProduct) me 2794 0 1 Z ??
502 2843 236 0 Wed01AM ?? 0:00.00 (MyProduct) me 2843 0 1 Z ??
502 2886 236 0 Wed01AM ?? 0:00.00 (MyProduct) me 2886 0 1 Z ??
...
502 13711 236 0 Thu11PM ?? 0:00.00 (MyProduct) me 13711 0 1 Z ??
502 13770 236 0 Thu11PM ?? 0:00.00 (MyProduct) me 13770 0 1 Z ??
502 14219 …Run Code Online (Sandbox Code Playgroud) 首先要做的事情.我的系统信息和版本:
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 13.04
Release: 13.04
Codename: raring
$ sudo docker version
Client version: 0.9.0
Go version (client): go1.2.1
Git commit (client): 2b3fdf2
Server version: 0.9.0
Git commit (server): 2b3fdf2
Go version (server): go1.2.1
$ lxc-version
lxc version: 0.9.0
$ uname -a
Linux ip-10-0-2-86 3.8.0-19-generic #29-Ubuntu SMP Wed Apr 17 18:16:28 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
Run Code Online (Sandbox Code Playgroud)
在它内部的过程变成僵尸之后,我无法阻止容器.升级到docker 0.9.0后,我的服务器上看到了大量的僵尸.例:
$ ps axo stat,ppid,pid,comm | grep -w defunct
Zl 25327 …Run Code Online (Sandbox Code Playgroud) 使用python-daemon时,我正在创建子进程likeo:
import multiprocessing
class Worker(multiprocessing.Process):
def __init__(self, queue):
self.queue = queue # we wait for things from this in Worker.run()
...
q = multiprocessing.Queue()
with daemon.DaemonContext():
for i in xrange(3):
Worker(q)
while True: # let the Workers do their thing
q.put(_something_we_wait_for())
Run Code Online (Sandbox Code Playgroud)
当我用Ctrl-C或SIGTERM等杀死父守护进程(即不是Worker)时,孩子们不会死.怎么杀了孩子?
我的第一个想法是使用atexit杀死所有的工人,喜欢:
with daemon.DaemonContext():
workers = list()
for i in xrange(3):
workers.append(Worker(q))
@atexit.register
def kill_the_children():
for w in workers:
w.terminate()
while True: # let the Workers do their thing
q.put(_something_we_wait_for())
Run Code Online (Sandbox Code Playgroud)
但是,守护进程的孩子们处理起来很棘手,我不得不考虑如何做到这一点并提出意见.
谢谢.