[ Javaクラス高速起動計画へ戻る ]
Javaクラス高速起動計画における最初の開発プログラム(開発コード"Mercury")です。
コマンドラインからJavaのクラスを起動します。マシン上で1つ起動しておくJava仮想マシン部分と、コマンドを要求するリクエストエントリー部分からなります。両者はソケットを介して通信します。
2003年8月17日
配布形態 | 配布ファイル名 | 備考 |
---|---|---|
バイナリ配布 | mercury-0.2.tar.gz | リクエストエントリ部はWin32版のみ |
ソース配布 | mercury-0.2-src.tar.gz |
jcl.exeがもしかするとWindows95/98/Me系では動作しないかもしれません。使用しているACEライブラリのドキュメントを見ると95系で動作するためには今回使用していないデファインが1つ必要らしいのです。
2003年3月8日
プログラム | ファイル名 | 対象OS | 備考 |
Java仮想マシン部 | Mercury-0.1-2.jar | Java 2 Platform | |
リクエストエントリー部 | jcl.exe | Windows | |
jcl | Linux x86 | N/A |
プログラム | ファイル名 | |
Java仮想マシン部 | Main.java | |
ListenerThread.java | ||
CommandDispatcher.java | ||
リクエストエントリー部 | jcl.cpp | Windows/Linux/Solaris他共通 |
GPLに従います。
Java仮想マシン部は、以下の4つのJavaクラスから構成されます。
ソケットを使用します。デフォルトはポート番号2345を使用します。コマンドラインからポート番号を指定可能です。リクエストの書式は以下のとおりです。
command + {args}* + CR + LF command: [A-Z] args: [^ ][^ ]*
本バージョンで用意しているリクエストは次の2つです。
command | C |
argsの数 | 1つ |
args内容 | 検索パスとして追加したいパス。URL表記で指定する。パスにディレクトリを指定するときは、最後の文字が'/'でなくてはならない。'/'が末尾にない場合、JAR形式アーカイブファイルを指定したことになる。 Windows OSの場合、ドライブ指定は、file:/<ドライブ文字>:/path/to/class/ と指定する。 |
command | R | |
argsの数 | 2つ以上 | |
argsの内容 | 1つ目 | 起動したいクラス名(FQCN) |
2つ目 | 起動したいメソッド名(staticメソッドでかつ引数がString[]1つを取るものでなくてはならない) | |
3つ目以降 | 2つ目で指定したメソッドの引数として渡す文字列 |
リクエストエントリー部は、Java仮想マシン部へリクエストをソケット経由で通知するプログラムです。これもJavaで書けるのですが、それでは毎回実行するたびにJava仮想マシンを動かすことになって目的が果たせません。Javaプログラムを実行するOS上でもっとも素早く起動できるもの(C/C++)を使って作成します。
リクエストエントリ部はコマンドラインで実行し、ソケット経由でリクエストをJava仮想マシン部へ通知します。コマンドラインオプションには、ソケットで送るリクエスト文字列をそのまま記述します。
当初、Windows用リクエストエントリー部はWinSockを使い、Linux用リクエストエントリー部はBSD Socketを使っていました。同じロジックを実装するのに、2つのソースを書いて保守する必要がありました。これに新たなOSを加えるのは非常に面倒です。また、ソケットAPIはC言語のAPIで低レベルな記述を要求されます。そこで、OSの違いをラップした上にC++クラスライブラリとしてソケットAPIを提供するACEを使用することにしました。
ACEのインストールやプログラミングについては以下を参照下さい。
ソースコードをWindows、Linuxその他のOSで共通化するために、ACEを使ってプログラミングしたものです。ソケット部分のコード(エラー処理は省いた)は以下のようなものになります。
ACE_SOCK_Connector connector; ACE_SOCK_Stream stream; ACE_INET_Addr addr(PORT_NUMBER, HOST_NAME); connector.connect(stream, addr); const char* buffer = "Message to send"; stream.send_n(buffer, ACE_OS::strlen(buffer) + 1); char recvBuffer[256]; for (ssize_t n; (n = stream.recv(recvBuffer, sizeof recvBuffer)) > 0; ) { // 受信処理 } stream.close(); // 終了処理 |
ACE_INET_Addrクラスがポート番号とホスト名やIPアドレスを扱います。バイトオーダを気にしなくてもよいし、コーディングが1行で済んでしまうのでとても楽です。接続もACE_SOCK_Connectorクラスのconnectメンバ関数1つでOKです。送信・受信はACE_SOCK_Streamクラスのsend(send_n)/recv(recv_n)メンバ関数で行えます。
mercury$ g++ -I/usr/local/include -L/usr/local/lib/ace -lACE -o jcl jcl.cpp mercury$
以下、UNIXシェル上での操作で例示していますが、Windows上のDOSプロンプト上での操作でも同じです。
mercury$ java -jar mercury-0.2.jar Java Fast Launch Program 'Mercury' $Date:2003/08/17 14:55:56 $ Copyright (C) 2002-2003, TAKAHASHI,Toru <torutk@alles.or.jp> Using port:2345 about to wait
まずMainクラスを実行します。
実行したいクラスファイルが置かれている基点ディレクトリをJava仮想マシン部に追加します。追加なので、一度設定したパスは以降有効となります。
$ jcl C file:/home/torutk/myclasses/ Response:SUCCESS $
Windowsの場合URL形式でディレクトリを指定する場合、file:/<ドライブレター>:/ディレクトリ/のように指定します。
E:\> jcl C file:/E:/home/torutk/myclasses/ Response:SUCCESS E:\
実行したいクラス名、起動メソッド、引数をJava仮想マシン部へ通知します。
$ jcl R Hello main Mercury Response:SUCCESS $
実行したクラスの標準出力(System.out)は、Java仮想マシン部のコンソールに表示されます。
mercury$ java -cp Mercury-0.1-1.jar Main Java Fast Launch Program 'Mercury' $Date:2003/08/17 14:55:56 $ Copyright (C) 2002-2003, TAKAHASHI,Toru <torutk@alles.or.jp> Using port:2345 about to wait opened socket from client about to wait opened socket from client Hello, Mercury about to wait
起動したクラスが終了時にSystem.exit()を呼んでしまうと、Java仮想マシン部自身も終了してしまいます。これはなんとか防ぎたいものです。そこで、セキュリティマネージャとアクセス権の設定によってSystem.exit()を回避します。
grant { permission java.lang.RuntimePermission "createClassLoader"; // 1 permission java.io.FilePermission "<<ALL FILES>>", "read"; // 2 permission java.net.SocketPermission "localhost", "accept, listen"; // 3 }; |
mercury$ java -jar mercury-0.2.jar -Djava.security.manager -Djava.security.policy=jcl.policy about to wait
System.exit(int)を呼び出しているクラスの場合、実行しようとするとexitVMのチェックに失敗してエラーとなります。
クラスパス上にあるクラスファイルをロードした場合、ポリシーファイルの内容に関わらずSystem.exit()を起動できる権限が付与されてしまいます。
コマンドラインから、簡単なSwingを使ったアプリケーションを実行する時間を計測しました。
計測対象マシン・スペック
CPU: MMX Pentium 166MHz
Memory: 96MB
OS: Linux 2.4.18(debian), XFree86 3.3
(1) コマンドラインからjavaコマンドによる起動時間
1回目:34秒、2回目:29秒、3回目:29秒
(2) Javaランチャー使用による起動時間
ランチャー起動時間:5秒
1回目:25秒、2回目:1秒、3回目:1秒
Java高速起動ツール開発のToDoです。要望がありましたら追加いたします。