このページで解決しない高度なJavaのシステム障害はJaTSにお任せください

Trouble 11: Javaから別プロセスを動かせません



<Q11-1>Runtime.exec()でシェルスクリプトを繰り返し実行するとRuntime.exec()がブロックしたままになってしまいます。


<発生環境>
OS RedHatLinux6.2J
JDK JDK1.3.1
Vender Sun
<A11-1>
根本的な原因と対策方法は不明のまま。
発生パターンとして、小さなシェルスクリプトを連続して実行すると現象が発生しやすい傾向があります。
この発生パターンから、回避策として一回の処理を1つのシェルスクリプトにまとめてRuntime.exec()の呼び出し回数を減らしてみたところ、現象が発生しなくなりました。
ただしこの回避策は、根本的な原因を解決したものではないので、すべてのケースで有効である確証は取れていません。
Page Top

<Q11-2>Javaからシェルスクリプトを起動することができません。


<発生環境>
OS Solaris
JDK JDK1.3
Vender Sun
<A11-2>
以下のように、シェルコマンドからシェルスクリプトを起動するようにすることで解決します。
String cmd[] = {"/bin/sh", "-exec", "hogehoge.sh"};
Process proc_ = Runtime.getRuntime().exec(cmd);
この方法でも、標準出力に対して出力を行うシェルスクリプトを起動するとうまくいかないようです。これはWindowsのバッチ起動でも同様の問題が起きています。
この問題を回避するため、標準出力に出力する代わりに、テンポラリファイルに出力するなどの工夫が必要です。
Page Top

<Q11-3>java.util.Timerクラスに登録したTimerTaskの1つを、Thread.sleep()メソッドで停止させたところ、他のTimerTaskが実行されなくなってしまいました。


<発生環境>
OS Any
JDK JDK1.3.0
Vender Any
<A11-3>
Timerクラスが、TimerTaskを順に処理しているためです。

Timerクラスは、登録されたTimerTaskを連続して実行するための唯一のスレッドを持ちます。
よって、現在実行中のTimerTaskの処理が終わらない限り、次のTimerTaskが実行されることはありません。
このため1つのTimerTaskがスリープしている間は、その後に実行される予定のTimerTaskは永遠に待たされることになります。

よって、TimerTaskでは停止もしくは長い処理を行うべきではありません。

もし必要な場合は、TimerTaskから別のスレッドを起動してその中で実行する様にすることで問題を回避できます。
Page Top

<Q11-4>java.util.TimerTaskをcancel()していないのにIllegalStateException("Timer already cancelled.")が発生してしまいます。

TimerTaskを定期的に登録するようなシステムで、あるとき以下の例外が発生しました。

IllegalStateException : Timer already cancelled.

(以下、java.util.Timer#schedule() で終わるスタックトレース)
java.util.Timer#cancel()を呼び出した後にjava.util.Timer#schedule()を呼び出すとこの例外が発生するらしいのですが、そもそもcancel()を呼び出すコードは実装していません。

<発生環境>
OS Any
JDK 1.4.2
Vender Any
<A11-4>
java.util.TimerTask#run()内でキャッチされない例外が発生している可能性があります。

TimerはTimerTaskを実行するためにTimerThreadというスレッドを持っています。 このTimerThreadが登録されたTimerTaskを実行するのですが、TimerTask#run()内でキャッチされない例外が発生すると、TimerThreadが例外をキャッチし、Timerに対してcancel()処理を行ないます。この結果、全てのTimerTaskがキャンセルされます。

よって覚えのないIllegalStateExceptionが発生する場合、TimerTask#run()内で例外が発生している可能性が考えられます。

対処方法としては、以下の方法が考えられます。

1.TimerTaskのrun()メソッドを、例外が発生しないようなコードに書き換える。
2.TimerTaskのrun()メソッド内の例外を正しくキャッチ/処理する。
3.schedule()を呼び出す箇所でIllegalStateExceptionをキャッチし、Timerを再生成するようにする。
Page Top

<Q11-5>Runtime#exec(String) で IOException が発生して、外部コマンドが実行できません。


<発生環境>
OS Solaris、Linux
JDK 1.4.1、1.4.2
Vender Sun
<A11-5>
コマンドを指定するパスに空白文字が含まれていませんか?
Runtime#exec(String)では空白文字は引数との区切り文字に解釈されてしまいます。 代わりに Runtime#exec(String[]) を使って下さい。

以下は"/my bin"というディレクトリの"touch"コマンドを引数"test.txt"で実行した例です。

失敗例:
 String command = "/my bin/touch test.txt";
 Runtime.getRuntime().exec(command);
(実行すると、「java.io.IOException: /my: not found」が発生します)

成功例:
 String[] command = {"/my bin/touch", "test.txt"};
 Runtime.getRuntime().exec(command);

Page Top

<Q11-6>Runtime.exec()で起動したJavaアプリケーションがしばらくして停止してしまいます。


<発生環境>
OS Win98OSR2
JDK JDK1.3.0
Vender Sun
<A11-6>
Runtime.exec()で起動された子プロセスが標準出力に出力を行っているためです。
親-子関係になったVM間のバッファサイズは1024バイトであり、それ以降を出力しようとするとブロックし、子プロセスの動作が停止してしまいます。
そのため、子プロセスは標準出力に表示しないか、もしくは親プロセスでVM間のバッファのストリームを読み捨てる必要があります。
Page Top

<Q11-7>java.lang.Runtime.exec()を複数回呼ぶと、execが立ち上げたスレッドが無限ループに入ることがあります。2回で起きることもあるし、100回以上ループする場合もあります。

しかし、Windows2000上では1000回ループさせても問題はありませんでした。

<発生環境>
OS Red Hat Linux 6.2
JDK JDK1.3β
Vender IBM
<A11-7>
SunのVMに変更し、execを使用するのは1つのVMにつき1回のみとすることで、解決できます。
Page Top

<Q11-8>Runtime#exec()を使用すると、OutOfMemoryErrorが発生することがあります。起動しようとしている外部プログラムはごく小さなもので、それに対して十分な空きメモリはあります。

Runtime#exec()を使用すると、OutOfMemoryErrorが発生することがあります。起動しようとしている外部プログラムはごく小さなもので、それに対して十分な空きメモリはあります。

<発生環境>
OS Solaris
JDK 1.4.1
Vender Sun
<A11-8>
起動元JavaVMが“太っている”可能性があります。

JavaVMのUNIX実装(Solaris、Linux)では外部プロセスの起動にfork()、exec()システムコールを使用します(※)。従って大量のメモリを使用しているなど、起動元プロセスが太った状態にあると、外部プログラムのサイズによらずforkに失敗することがあります。

ps、prstatコマンドなどで起動元プロセスのメモリサイズを確認してください。

起動元プロセスのメモリ大量消費が確認できた場合、
(1)swap領域を増やす
(2)物理メモリを増設する
(3)起動元プロセスをシェイプアップする
などの対処を行なう必要があります。

※実際にはfork1()を使用するため、単純にプロセス全体のコピーが作成されるわけではありません。
Page Top

注意:本文書の内容に誤りがあり、またこの文書によって不利益を被っても、
Acroquest Technology 株式会社は一切関知いたしません。

  • 現象別Index
  • 原因別Index

Find Bugsバグ詳細

Find Bugs Bug Descriptions日本語版

RSSで更新情報を取得する

RSSとは、ホームページの更新情報を配信する為のフォーマットです。
RSSを利用すると、登録したページの情報が更新された場合に、更新情報を自動的に受け取る事ができます。

詳細

弊社小森が執筆致しました

Javaでオブジェクト指向開発

Javaプログラミング言語習得において、新人プログラマーの最初の障害は「オブジェクト指向の壁」です。
本書は、Javaのソフトウェア開発を中心に事業を発展させてきたAcroquest社の新人教育セミナーを加筆・書籍化したもので、大卒の新人に対して、ゼロからJava言語を教えてきた実績をフィードバックしています。

メールマガジン配信中

Javaトラブルシューティングのメルマガをはじめました!是非ご購読ください

詳細