ページの先頭行へ戻る
Interstage Application Server/Interstage Web Server 使用上の注意
Interstage

2.12.7 java.lang.Runtime.exec()使用時の注意事項

java.lang.Runtimeクラスのexecメソッドで、別プログラムを実行する際の注意事項を、以下で説明します。


仮想メモリ不足による例外発生

仮想メモリ領域のサイズは、実メモリサイズとswap 領域サイズの合計であるため、仮想メモリ領域を使用しているtmpfs(例:/tmp)に大容量のファイルを配置すると、メモリを使用していない場合でも、仮想メモリ領域が減少します。


Javaでは、javaコマンドの "-Xmx"オプションなどでJava が使用するメモリ領域を予約します。
そのため、実際には予約されているだけで使用されていない場合でも、他の用途にメモリを使用することはできません。
それにより、メモリに空きがあるように見える場合でも、子プロセスの起動に必要なメモリを獲得できず子プロセスの起動に失敗し、java.io.IOExceptionが発生する場合があります。


仮想メモリ領域を使用しているtmpfs(例:/tmp)に大容量のファイルを配置している。または、"-Xmx"オプションなどで大きな領域を指定しているなど、仮想メモリ領域が不足している状態で、Runtimeクラスのexecメソッドで子プロセスを実行するとjava.io.IOExceptionが発生する場合があります。


この場合、次のいずれかの対処を行ってください。

ファイルディスクリプタ不足による例外発生

オープンされたファイルが多い状態でRuntimeクラスのexecメソッドで子プロセスを実行すると、ファイルディスクリプタ(fd)が不足し、java.io.IOExceptionなどの例外が発生する場合があります。
この場合は、子プロセスに対する入出力ストリームを明示的にクローズするようにプログラムを見直してください。
次の例を参考にしてください。


子プロセスに対する入出力ストリームのクローズ処理

Process p = Runtime.getRuntime().exec(...);
    :
p.waitFor();                 // 子プロセスの終了を待つ
p.getInputStream().close();  // 標準出力ストリームをクローズ
p.getErrorStream().close();  // 標準エラー出力ストリームをクローズ
p.getOutputStream().close(); // 標準入力ストリームをクローズ

子プロセスのストリームに対する入出力

親プロセスがRuntime.execメソッドで子プロセスを実行する際、子プロセスの標準入力、標準出力、標準エラー出力のそれぞれに対してパイプを作成します。
このため、子プロセスが、標準入力からの入力を待っている状態になったり、標準出力および標準エラー出力へ出力できない状態になったりした場合、子プロセス自身の処理が進まず、子プロセスがブロックされるか、デッドロックになる場合があります。


したがって、子プロセスの標準入力への書込みおよび、標準出力、標準エラー出力からの読込みを行う処理を確実に迅速に行うようにしてください。


次の例を参考にして、プログラミングしてください。


子プロセスの標準出力、標準エラー出力に対する入力処理の例

import java.io.*;

public class ProcessSample {
    public static void main(String[] args) {
        new ProcessSample();
    }

    public ProcessSample() throws Exception {
        // "sort data.txt"を、子プロセスとして実行
        // sortは、テキストをソートするコマンド
        // data.txtは、javaプロセスのカレントディレクトリ上のテキストファイル
        Process p = Runtime.getRuntime().exec("sort data.txt");

        // 子プロセスの標準出力および標準エラー出力を入力するスレッドを起動
        new StreamThread(p.getInputStream(), "stdout.txt").start();
        new StreamThread(p.getErrorStream(), "stderr.txt").start();

        // 子プロセスの終了を待つ
        p.waitFor();
    }

    /**
     *子プロセスの出力ストリームから入力し、ファイルに出力するスレッド
     */
    class StreamThread extends Thread {
        private static final int BUF_SIZE = 4096;
        private InputStream in;
        private BufferedOutputStream out;

        public StreamThread(InputStream in, String outputFilename) throws IOException {
            this.in  = in;
            this.out = new BufferedOutputStream(new FileOutputStream(outputFilename));
        }

        public void run(){
            byte[] buf = new byte[BUF_SIZE];
            int size = -1;
            try{
                while((size = in.read(buf, 0, BUF_SIZE)) != -1){
                    out.write(buf, 0, size);
                }
            }catch(IOException ex){
                ex.printStackTrace();
            }finally{
                try{in.close();} catch(IOException ex){}
                try{out.close();}catch(IOException ex){}
            }
        }
    }
}