Wrapper ネイティブ Exec の概要

概要

WrapperManager.exec()] 関数は、 [Java-Runtime.exec()]あるいは[Java-ProcessBuilder]の代替え案であり、 新しいプロセスを生成するのに[fork()]メソッドを 利用して、一部のプラットフォームでメモリを無駄に消費する不利な点があります。 それらのプラットフォーム上での問題は、サイドプロセスを開始したいペアレント(親)プロセスにおいて、 [fork()]がチャイルド(子)用にペアレント(親)のメモリヒープのクローンを作成します。 そのため、短時間で消費メモリが倍になります。 システムメモリの割り当て量に近い、わりと大きいアプリケーションが与えられると、 [ls]のような、小さいアプリケーションの作成にも失敗する可能性があります。 あるいは、ハードディスクへそのメモリのスワッピングが発生する可能性もあり、パフォーマンスが劇的に低下することになります。

もう一つの問題としては、ペアレント(親)から開始している間、チャイルド(子)のバインドやデタッチ(切り離し)を緩和することです。 もし Java プロセスが、期待どおりにしろ、予想外にしろ、終了する場合、 Wrapper は、まだ終了していない全てのバインドプロセスをクリーンします。

より良い一貫性のために、可能な限り、Java での[Runtime.exec()]関数に近い、 WrapperManager.exec()]関数が実装されました。

実行する

スタート

このセクションでは、コマンドをどのように実行するのかを説明します。 (さらに詳細は、このページを読み進めながら、ステップバイステップで説明していきます)

WrapperProcess p = WrapperManager.exec("ls -lisa");

上記は、[-l]、[-i]、[-s]や[-a]パラメーターで、[ls]コマンドを実行し、そのプロセスを表現する[WrapperProcess]オブジェクトをアサインします。

もし、バイナリ(あるいはスクリプト)ファイルの完全なフルパスが渡されていない場合、 システム PATH ディレクトリー同様に、そのカレント作業ディレクトリーが確認され、 最初に見つかったものが実行されます。 現在の作業ディレクトリーからの相対アドレス指定もサポートされています。

注意

exec]コマンドは、 単一の文字列(String)として、あるいは同様に、文字列群(StringArray)として、 どちらでのコマンドでも受け入れます。 文字列群(StringArray)の場合、各パラメーターは、単一の配列フィールド(a single array field)に配置されます。

プロセスの I/O

GUI アプリケーションでない限り、作成されたチャイルド(子)プロセスは、 OS のバックグランドで動作し、通常は見えません。 そのプロセスとコミニケーションするために、 [WrapperProcess]クラスは、 そのプロセスへの出力やエラーメッセージ、同様に、そのプロセスへの入力にアクセスするために、 3つのメソッドを提供します。

BufferedReader で、返されたストリームオブジェクト(StreamObject)をラップすることを推奨します。 リーダーを開けるには、下記のとおりに手順を進めてください。

BufferedReader br = new BufferedReader( new InputStreamReader(p.getWrapperProcessInputStream()));

これは、チャイルド(子)がその出力を書き出すインプットストリーム(InputStream)のリーダーを確立します。 エラーストリーム(ErrorStream)からデータを読む、あるいは、チャイルド(子)へデータを書き出すには、 この例に似たように処理を進めてください。

一旦、リーダー/ライターが確立されると、データを読み込む/書き込むことができるようになります。

String line;
while ((line = br.readLine()) != null)
{
    System.out.println(line);
}
br.close();

注意

この例を追うと、 そのチャイルド(子)プロセスが、自分側のストリームを閉じるまで、全てのデータが読み込まれます のでご注意ください。

チャイルド(子)プロセスのコンフィギュレーション

コマンドを実行するとき、 WrapperManager は、チャイルド(子)プロセスを設定する可能性を提供します。 これは、[WrapperProcessConfig]オブジェクトを、 [exec()]関数へ引き渡すことで行われます。 次のセクションでは、WrapperProcessConfiguration によって作成されるコンフィギュレーションについて説明します。

切り離されたプロセス

setDetached()」メソッドは、サブプロセスが Wrapper から「切り離されて」動作するのかを設定します。 もし、プロセスが「切り離された」とマークされた場合、Wrapper がシャットダウンする時、 そのプロセスを終了する必要はありません。 もし、「デタッチ(切り離し)」マークがない場合、Wrapper はチャイルド(子)プロセスの経過を追い、 そのペアレント(親)プロセスを終了するべき時には、そのチャイルド(子)プロセスの終了を試みます。

注意

デフォルトで、プロセスはそのペアレント(親)プロセスから切り離された状態で開始されません。

スタートタイプ

setStartType()」メソッドは、サブプロセスが OS によって、どのように開始されるのか、スタートタイプを指定します。

警告

このプロパティは Windows では無効です。

  • [FORK_EXEC] :

    UNIX/Linux 上で、チャイルド(子)プロセスを生成する一般的な手法です。 しかしながら、一部の OS(特に Solaris)上では、 このコールは、チャイルド(子)用に、初めにペアレント(親)のメモリを複製することになります。 z/OS 上では、このスタートタイプが Wrapper 初代リリースの時点でサポートされていません。 HP-UX システム上では、Wrapper は[fork()]ではなく、 [vfork]を使うように自動的に切り替えます。

  • [VFORK_EXEC] :

    チャイルド(子)プロセスがペアレント(親)プロセスとコードやデータを共有することができる場合に、 [vfork()]関数は、[fork()]とは異なります。 これは、 もし[vfork()]が誤用された場合、 ペアレント(親)プロセスのインテグリティ(整合性)にリスクを伴い、クローン動作が著しく加速します。 一部のシステム上では、[vfork]は[fork]と同じです。 z/OS 上では、このスタートタイプは Wrapper 初代リリースの時点でサポートされていません。

  • [POSIX_SPAWN] :

    プロセスが生成され、何もメモリ複製 POSIX_SPAWN API を起こしません。 これは、Linux、Solaris (10+)、AIX、z/OS、MacOS と FreeBSD 8+のみに有効です。(バージョン 3.5.46から)

  • [DYNAMIC] :

    このスタートタイプは、Wrapper が動作している OS 次第で最適なスタートタイプを選択します。 このプロパティは、POSIX_SPAWN の使用時に作業ディレクトリーの変更をサポートしていないため、作業ディレクトリの変更がサポートされないことも意味することに注意してください。 作業ディレクトリーの変更も利用できる試験的なプロパティ [wrapper.child.allowCWDOnSpawn] があります。

注意

デフォルト値は、スタートタイプ[DYNAMICでプロセスが起動されます。

作業ディレクトリー

setWorkingDirectory()」は、サブプロセスの作業ディレクトリーを指定するか、 サブプロセスがカレントプロセスの作業ディレクトリーを継承する場合には、「NULL」を設定します。

POSIX_SPAWN を利用中には、 作業ディレクトリーを直接設定することはできませんので、ご注意ください。 お薦めの回避策は、スクリプト内で動かしたいコマンドをラップして、 そのコマンドの実行前に、ディレクトリー変更をすることです。

#!/bin/sh

chdir $1
shift
$*

注意

もし、このプロパティが設定されない場合、 サブプロセスは、そのペアレント(親)プロセスから作業ディレクトリーを継承します。

wrapper.child.allowCWDOnSpawn プロパティ

wrapper.child.allowCWDOnSpawn]プロパティでは、 [POSIX_SPAWN]や[DYNAMIC] スタートタイプのとき、Wrapper が作業ディレクトリーの変更を試みるかをコントロールします。

このプロパティは実験的なもので、 ラップされたプロセスが Java ネイティブインターフェイス(JNI)コードを利用している場合、 問題を引き起こす可能性もあり、[POSIX_SPAWN] を使いチャイルド(子)プロセスの生成を試みることでしょう。

このプロパティのデフォルト値は「FALSE」に設定されます。

wrapper.child.allowCWDOnSpawn=TRUE

環境を設定する

setEnvironment()」メソッドは、作成されたサブプロセスの環境を指定します。

このフィールドは文字配列で、各エレメントは「名前=値」形式で、環境変数を設定します。

注意

もし、このプロパティが設定されない場合、 サブプロセスは、そのペアレント(親)プロセスから環境を継承します。

チャイルド終了にソフトタイムアウトを設定する

Wrapper バージョン 3.5.5 から、 各プロセスにそれぞれのソフトタイムアウトを指定することが可能になり、 Wrapper はチャイルド(子)プロセスに自力で終了する機会が与えられますが、 [java.lang.Process.destroy()]メソッドは常に強制シャットダウンを引き起こし、プロセスに自力で終了する機会を与えません。 Wrapper バージョン 3.5.5 より以前では、機能性を一定に保つために、タイムアウトは常にデフォルトで5秒でした。

このタイムアウトは、チャイルド(子)プロセスが[WrapperProcessConfig]クラスで作成されているときに指定することができます。

WrapperProcessConfig wpConfig = new WrapperProcessConfig().setSoftShutdownTimeout(10);

上記のコンフィギュレーション例では、そのコンフィギュレーションで作成されたとおり、 Wrapper を最大10秒間までチャイルド(子)プロセス待ちにさせます。 もし、チャイルドプロセスが10秒以内に終了しない場合、Wrapper はそのチャイルドプロセスを強制終了させます。

タイムアウトの可能な値は、次のとおりです。

  • [>0] :

    強制終了される前に、チャイルド(子)プロセスが自力で終了するまで、Wrapper が待機する秒数を指定します。

  • [0] :

    Wrapper が即座にチャイルド(子)プロセスの終了を強制します。

  • [-1] :

    Wrapper はチャイルド(子)プロセスを強制終了しませんが、 そのチャイルド(子)プロセスが自力で終了するまで永久に待機します。

アクティブユーザー用にチャイルド(子)プロセスを作成する

Windows 上で、 [WrapperProcessConfig.setCreateForActiveUser(boolean)]は、サービスが動作しているアクティブセッション(OS の「SE_TCB_NAME」権限を持つユーザー)ではなく、現在のアクティブセッション内で、チャイルド(子)プロセスが起動するかどうかを指定します。 Windows 以外のプラットフォーム上で、あるいはコンソールモードで起動されている場合、この設定は静かに無視されます。

デフォルト値は「FALSE」に設定されています。