代码之家  ›  专栏  ›  技术社区  ›  uckelman

什么会导致Java在Stase.Ext()之后继续运行?

  •  20
  • uckelman  · 技术社区  · 16 年前

    我有一个Java程序,它正在启动 ProcessBuilder 从另一个Java程序。 System.exit(0) 是从子程序调用的,但对于某些用户(在Windows上)来说 java.exe 与子进程关联的进程未终止。子程序没有关闭挂钩,也没有 SecurityManager 可能会停止 System.exit() 停止终止虚拟机。我无法在linux或windows vista上复制这个问题。到目前为止,只有两个windows xp用户和一个vista用户报告了这个问题,他们使用了两个不同的jre(1.6.0和1.6.0)。

    有人能解释一下为什么jvm在 系统退出() ,然后只在一些机器上?

    编辑1: 我让用户安装了jdk,这样我们就可以从有问题的vm获得一个线程转储。用户告诉我的是,只要他单击菜单中的“退出”项,vm进程就会从visualvm中消失,但是,根据windows任务管理器的说法,该进程并没有终止,无论用户等待多长时间(分钟、小时),它都不会终止。

    编辑2: 我已经确认了 Process.waitFor() 在父程序中,至少有一个有问题的用户不会返回。因此,总结一下:子vm似乎已经死了(visualvm甚至没有看到它),但是父vm仍然将进程视为活动的,windows也是。

    8 回复  |  直到 16 年前
        1
  •  6
  •   Andrew McVeigh    16 年前

    父进程有一个线程 致力于消费 儿童标准音和标准音 将输出传递到日志 文件)。据我所见,这些是 工作正常,因为我们看到 我们希望在中看到的所有输出 日志

    当我使用stdout/stderr时,我的程序没有从task mgr中消失。在我的例子中,如果我在调用system.exit()之前关闭了正在侦听的流,那么javaw.exe就会挂起。奇怪的是,它不是在给小溪写信…

    在我的例子中,解决方案是简单地刷新流,而不是在存在之前关闭它。当然,您可以在退出之前刷新并重定向回stdout和stderr。

        2
  •  7
  •   Molten Ice    9 年前

    如果您的代码(或您使用的库)有一个关闭挂钩或终结器没有完全完成,则可能会发生这种情况。

    更有力的(所以只能在极端情况下使用!)强制关机的方法是运行:

    Runtime.getRuntime().halt(0);
    
        3
  •  4
  •   Romain Hippeau    16 年前

    这里有几个场景…

    根据线程的定义 http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Thread.html

    当Java虚拟机启动时,通常会有一个非守护进程线程(通常调用名为某个指定类的main方法)。Java虚拟机继续执行线程,直到下列任何一个发生:

    1)调用了类运行时的exit方法,安全管理器允许执行exit操作。 2)所有不是守护进程线程的线程都已死亡,方法是从对run方法的调用返回,或者抛出传播到run方法之外的异常。

    另一种可能是调用了runfinalizersonexit方法。根据中的文件 http://java.sun.com/j2se/1.4.2/docs/api/java/lang/System.html 不赞成的这种方法本质上是不安全的。它可能会导致在其他线程同时操作这些对象时对活动对象调用终结器,从而导致不稳定的行为或死锁。 在Exchange中启用或禁用终结;这样做指定所有尚未被自动调用的终结器的终结器将在Java运行时退出之前运行。默认情况下,将禁用退出时的终结。 如果存在安全管理器,则首先调用其checkExit方法,并使用0作为其参数,以确保允许退出。这可能会导致SecurityException。

        4
  •  1
  •   Chris Dolan    16 年前

    也许是一个写得不好的定稿人?当我读到主题行时,第一个想到的是关闭钩子。推测:捕获InterruptedException并继续运行的线程是否会阻止退出进程?

    在我看来,如果问题是可重复的,那么您应该能够附加到jvm并获得显示挂起内容的线程列表/堆栈跟踪。

    你确定这孩子还真的在跑,而且这不仅仅是一个未读的僵尸进程吗?

        5
  •  1
  •   Michael Konietzka    16 年前

    父进程是否使用来自子进程的错误和输出流? 如果在某些操作系统下,子进程在stdout/stderr上打印出一些错误/警告,并且父进程不使用流,则子进程将阻塞并且无法到达system.exit();

        6
  •  1
  •   maxbit89    10 年前

    我也遇到了同样的问题,但对我来说,原因是我在使用远程调试(vmargs:-xdebug-xrunjdwp:transport=dt_socket,address=%port%,server=y,suspend=y),当我禁用此功能时,java.exe进程按预期退出。

        7
  •  0
  •   Stephen C    16 年前

    我认为所有明显的原因都被暂时覆盖了,例如终结器、关闭挂钩、没有正确地排出父进程中的标准输出/标准错误。你现在需要更多的证据来确定到底发生了什么。

    建议:

    1. 安装WindowsXP或Vista计算机(或虚拟机),安装相关的JRE和应用程序,并尝试重现问题。一旦您可以重现问题,请附加调试器或发送相关信号以将线程转储到标准错误。

    2. 如果您不能像上面那样重现问题,请让您的一个用户进行线程转储,并将日志文件转发给您。

        8
  •  0
  •   Dean Hiller    13 年前

    这里没有提到的另一个情况是,如果关闭钩子挂在某个东西上,那么在编写关闭钩子代码时要小心(如果第三方库也注册了挂起的关闭钩子)。

    院长