29

ProcessBuilder別の Java プログラムから 起動されている Java プログラムがあります。System.exit(0)子プログラムから呼び出されますが、一部のユーザー (Windows 上) ではjava.exe、子に関連付けられたプロセスが終了しません。子プログラムにはシャットダウン フックがなく、VM の終了をSecurityManager停止する可能性のあるもありません。System.exit()Linux または Windows Vista で問題を自分で再現できません。これまでのところ、この問題に関する報告は、2 つの異なる JRE (1.6.0_15 と 1.6.0_18) を使用している 2 人の Windows XP ユーザーと 1 人の Vista ユーザーからのものだけですが、彼らは毎回問題を再現することができます。

System.exit()の後に JVM が終了せず、一部のマシンでのみ終了する理由を誰かが提案できますか?

編集 1:問題のある VM からスレッド ダンプを取得できるように、ユーザーに JDK をインストールしてもらいました。ユーザーが私に言ったのは、メニューの「終了」項目をクリックするとすぐに VM プロセスが VisualVM から消えるということですが、Windows タスク マネージャーによると、プロセスは終了していません。ユーザーが (分、時間) 待機しても、終了することはありません。

編集 2:Process.waitFor()親プログラムでは、問題を抱えているユーザーの少なくとも 1 人に対して決して返らないことを確認しました。要約すると、子 VM は停止しているように見えますが (VisualVM はそれを認識していません)、親はまだプロセスを稼働中であると認識しており、Windows も同様です。

4

9 に答える 9

7

親プロセスには、子プロセスの STDOUT と STDERR のそれぞれを消費する専用のスレッドが 1 つあります (これにより、その出力がログ ファイルに渡されます)。ログに表示されるはずのすべての出力が表示されているため、私が見る限り、これらは適切に機能しています。

stdout/stderr を使用しているときに、プログラムがタスク マネージャーから消えないという同様の問題がありました。私の場合、system.exit() を呼び出す前にリッスンしていたストリームを閉じると、javaw.exe がハングアップしました。奇妙なことに、それはストリームへの書き込みではありませんでした...

私の場合の解決策は、存在する前にストリームを閉じるのではなく、単純にストリームをフラッシュすることでした。もちろん、いつでもフラッシュしてから、終了する前に stdout と stderr にリダイレクトすることができます。

于 2010-09-12T22:25:30.077 に答える
4

ここにいくつかのシナリオがあります...

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Thread.htmlのスレッドの定義による

..。

Java仮想マシンが起動すると、通常、デーモン以外のスレッドが1つ存在します(通常、指定されたクラスのmainという名前のメソッドを呼び出します)。Java仮想マシンは、次のいずれかが発生するまでスレッドを実行し続けます。

1)クラスRuntimeのexitメソッドが呼び出され、セキュリティマネージャがexit操作の実行を許可しました。2)デーモンスレッドではないすべてのスレッドが、runメソッドの呼び出しから戻るか、runメソッドを超えて伝播する例外をスローすることによって停止しました。

もう1つの可能性は、メソッドrunFinalizersOnExitが呼び出された場合です。http://java.sun.com/j2se/1.4.2/docs/api/java/lang/System.htmlのドキュメントに従って非 推奨。この方法は本質的に安全ではありません。ライブオブジェクトでファイナライザーが呼び出され、他のスレッドがそれらのオブジェクトを同時に操作していると、動作が不安定になったり、デッドロックが発生したりする可能性があります。終了時のファイナライズを有効または無効にします。そうすることで、まだ自動的に呼び出されていないファイナライザーを持つすべてのオブジェクトのファイナライザーが、Javaランタイムが終了する前に実行されるように指定されます。デフォルトでは、終了時のファイナライズは無効になっています。セキュリティマネージャが存在する場合、そのcheckExitメソッドは、終了が許可されていることを確認するために、引数として0を指定して最初に呼び出されます。これにより、SecurityExceptionが発生する可能性があります。

于 2010-04-10T21:41:06.897 に答える
1

親プロセスは子プロセスからのエラーストリームと出力ストリームを消費しますか?一部のOSで、子プロセスがstdout / stderrでエラー/警告を出力し、親プロセスがストリームを消費していない場合、子プロセスはブロックされ、System.exit()に到達しません。

于 2010-04-10T21:36:14.343 に答える
1

ファイナライザーの書き方が悪いのでしょうか?件名を読んだとき、シャットダウン フックが最初に思い浮かびました。推測: InterruptedException をキャッチしてとにかく実行し続けるスレッドは、終了プロセスを保留しますか?

問題が再現可能であれば、JVM にアタッチして、何がハングアップしたかを示すスレッド リスト/スタック トレースを取得できるはずです。

子がまだ実際に実行されていること、およびそれが未取得のゾンビ プロセスではないことは確かですか?

于 2010-04-10T20:11:58.233 に答える
0

ここで言及されていない別のケースは、シャットダウン フックが何かにハングアップする場合です。シャットダウン フック コードを記述する際には注意してください (サード パーティのライブラリが同様にハングしているシャットダウン フックを登録している場合)。

ディーン

于 2013-01-28T19:31:51.717 に答える
0

明らかな原因はすべて暫定的にカバーされていると思います。例: ファイナライザー、シャットダウン フック、親プロセスの標準出力/標準エラーを正しく排出しない。何が起こっているのかを理解するには、さらに多くの証拠が必要です。

提案:

  1. Windows XP または Vista マシン (または仮想マシン) をセットアップし、関連する JRE とアプリをインストールして、問題の再現を試みます。問題を再現できたら、デバッガーをアタッチするか、関連するシグナルを送信してスレッド ダンプを標準エラーに取得します。

  2. 上記のように問題を再現できない場合は、ユーザーの 1 人にスレッド ダンプを取得してもらい、ログ ファイルを転送してもらいます。

于 2010-04-11T04:12:01.743 に答える