对于Linux上的进程,kill -9怎么可能没有效果?

时间:2009-03-29 14:39:22

标签: linux process sysadmin kill

我正在编写一个插件,以便在您访问网站时自动突出显示文本字符串。这就像突出显示搜索结果,但自动和许多单词;它可以用于过敏的人,使单词真正脱颖而出,例如,当他们浏览食物网站时。

但我有问题。当我尝试关闭一个空的,新鲜的FF窗口时,它会以某种方式阻止整个过程。当我终止进程时,所有窗口都消失了,但Firefox进程保持活动状态(父PID为1,不监听任何信号,打开大量资源,仍然占用CPU,但不会让步)。

所以有两个问题:

  1. 如果一个进程不听kill -9(无论是用户还是root用户)怎么可能?

  2. 除了重启之外,我能做些什么吗?

  3. [编辑]这是违规的过程:

    USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    digulla  16688  4.3  4.2 784476 345464 pts/14  D    Mar28  75:02 /opt/firefox-3.0/firefox-bin
    

    ps -ef | grep firefox

    相同
    UID        PID  PPID  C STIME TTY          TIME CMD
    digulla  16688     1  4 Mar28 pts/14   01:15:02 /opt/firefox-3.0/firefox-bin
    

    这是剩下的唯一过程。正如你所看到的,它不是一个僵尸,它正在运行!它不会听杀-9,无论我是用PID还是名字杀了!如果我尝试与strace建立联系,那么strace也会挂起并且无法被杀死。也没有输出。我的猜测是FF挂起了一些内核例程但是哪个?

    [EDIT2]根据sigjuice的反馈:

    ps axopid,comm,wchan
    

    可以显示进程挂起的内核例程。就我而言,有问题的插件是Beagle Indexer(openSUSE 11.1)。禁用该插件后,FF又是一只快速而快乐的狐狸。

7 个答案:

答案 0 :(得分:124)

如对OP的评论中所述,STAT的进程状态(D)表示进程处于“不间断睡眠”状态。在现实世界中,这通常意味着它在等待I / O并且不会/不会做任何事情 - 包括死亡 - 直到I / O操作完成。

D状态的进程通常只会在操作完成之前的几分之一秒内返回R / S。根据我的经验,如果进程陷入D,它通常会尝试与无法访问的NFS或其他远程文件系统进行通信,尝试访问发生故障的硬盘驱动器,或者通过以下方式使用某些硬件一个片状设备驱动程序。在这种情况下,恢复并允许进程死亡的唯一方法是让fs / drive / hardware备份并运行,以便I / O可以完成或放弃并重启系统。在NFS的特定情况下,安装也可能最终超时并从I / O操作返回(带有故障代码),但这取决于安装选项,并且将NFS安装设置为永久等待是很常见的

这与僵尸流程不同,僵尸流程的状态为Z

答案 1 :(得分:8)

仔细检查父ID是否为1.如果不是,并且这是firefox,请先尝试sudo killall -9 firefox-bin。之后,尝试使用sudo killall -9 [process-id]单独删除特定进程ID。

  

如果一个进程不能监听kill -9(用户还是root用户),它怎么可能呢?

如果某个进程已经<defunct>,然后变为zombie且父级为1,则无法手动将其删除;只有init才可以。僵尸进程已经死亡并且已经消失 - 它们已经失去了被杀的能力,因为它们不再是进程,只有进程表条目及其相关的退出代码,等待收集。您需要杀死父级,并且由于显而易见的原因,您无法杀死init

但请参阅here了解更多一般信息。重启会自然会杀死所有东西。

答案 2 :(得分:1)

是否有可能在你杀死它的过程中重启这个过程(例如通过init)?

您可以轻松查看此内容。如果在kill -9 PID之后PID相同,则该过程未被终止,但如果已经更改,则该过程已重新启动。

答案 3 :(得分:1)

我最近陷入了Double Fork的陷阱,并在最终找到答案之前登陆了这个页面。即使问题不一样,症状也是一样的:

  • WYKINWYT:你所杀的不是你的想法

下面根据SNMP守护程序的示例

显示最小测试代码
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

int main(int argc, char* argv[])
{
    //We omit the -f option (do not Fork) to reproduce the problem
    char * options[]={"/usr/local/sbin/snmpd",/*"-f","*/-d","--master=agentx", "-Dagentx","--agentXSocket=tcp:localhost:1706",  "udp:10161", (char*) NULL};

    pid_t pid = fork();
    if ( 0 > pid ) return -1;

    switch(pid)
    {
        case 0: 
        {   //Child launches SNMP daemon
            execv(options[0],options);
            exit(-2);
            break;
        }
        default: 
        {
            sleep(10); //Simulate "long" activity

            kill(pid,SIGTERM);//kill what should be child, 
                              //i.e the SNMP daemon I assume
            printf("Signal sent to %d\n",pid);

            sleep(10); //Simulate "long" operation before closing
            waitpid(pid);
            printf("SNMP should be now down\n");

            getchar();//Blocking (for observation only)
            break;
        }
    }
    printf("Bye!\n");
}

在第一阶段,主进程(7699)启动SNMP守护进程(7700),但我们可以看到这个现在是 Defunct / Zombie 。除此之外,我们可以看到另一个过程(7702),其中包含我们指定的选项

[nils@localhost ~]$ ps -ef | tail
root       7439      2  0 23:00 ?        00:00:00 [kworker/1:0]
root       7494      2  0 23:03 ?        00:00:00 [kworker/0:1]
root       7544      2  0 23:08 ?        00:00:00 [kworker/0:2]
root       7605      2  0 23:10 ?        00:00:00 [kworker/1:2]
root       7698    729  0 23:11 ?        00:00:00 sleep 60
nils       7699   2832  0 23:11 pts/0    00:00:00 ./main
nils       7700   7699  0 23:11 pts/0    00:00:00 [snmpd] <defunct>
nils       7702      1  0 23:11 ?        00:00:00 /usr/local/sbin/snmpd -Lo -d --master=agentx -Dagentx --agentXSocket=tcp:localhost:1706 udp:10161
nils       7727   3706  0 23:11 pts/1    00:00:00 ps -ef
nils       7728   3706  0 23:11 pts/1    00:00:00 tail

模拟10秒后,我们将尝试杀死我们所知道的唯一过程(7700)。我们最后用 waitpid()取得了成功。但是Process 7702还在这里

[nils@localhost ~]$ ps -ef | tail
root       7431      2  0 23:00 ?        00:00:00 [kworker/u256:1]
root       7439      2  0 23:00 ?        00:00:00 [kworker/1:0]
root       7494      2  0 23:03 ?        00:00:00 [kworker/0:1]
root       7544      2  0 23:08 ?        00:00:00 [kworker/0:2]
root       7605      2  0 23:10 ?        00:00:00 [kworker/1:2]
root       7698    729  0 23:11 ?        00:00:00 sleep 60
nils       7699   2832  0 23:11 pts/0    00:00:00 ./main
nils       7702      1  0 23:11 ?        00:00:00 /usr/local/sbin/snmpd -Lo -d --master=agentx -Dagentx --agentXSocket=tcp:localhost:1706 udp:10161
nils       7751   3706  0 23:12 pts/1    00:00:00 ps -ef
nils       7752   3706  0 23:12 pts/1    00:00:00 tail

在给getchar()函数赋予一个字符之后,我们的主进程终止了,但是带有pid 7002的SNMP守护进程仍然在这里

[nils@localhost ~]$ ps -ef | tail
postfix    7399   1511  0 22:58 ?        00:00:00 pickup -l -t unix -u
root       7431      2  0 23:00 ?        00:00:00 [kworker/u256:1]
root       7439      2  0 23:00 ?        00:00:00 [kworker/1:0]
root       7494      2  0 23:03 ?        00:00:00 [kworker/0:1]
root       7544      2  0 23:08 ?        00:00:00 [kworker/0:2]
root       7605      2  0 23:10 ?        00:00:00 [kworker/1:2]
root       7698    729  0 23:11 ?        00:00:00 sleep 60
nils       7702      1  0 23:11 ?        00:00:00 /usr/local/sbin/snmpd -Lo -d --master=agentx -Dagentx --agentXSocket=tcp:localhost:1706 udp:10161
nils       7765   3706  0 23:12 pts/1    00:00:00 ps -ef
nils       7766   3706  0 23:12 pts/1    00:00:00 tail

结论

我们忽略双叉机制这一事实让我们认为kill操作没有成功。但实际上我们只是杀了错误的过程!!

添加 -f 选项(不要(双)叉)全部按预期进行

答案 4 :(得分:0)

sudo killall -9 firefox

应该工作

编辑:[PID]改为firefox

答案 5 :(得分:0)

ps -ef | grep firefox; 你可以看到3个进程,将它们全部杀掉。

答案 6 :(得分:0)

你也可以做一个pstree并杀死父母。这可以确保您获得整个违规流程树,而不仅仅是叶子。