[ Javaクラス高速起動計画へ戻る ]

Mercury版Javaクラス高速起動ツール


概要

Javaクラス高速起動計画における最初の開発プログラム(開発コード"Mercury")です。

コマンドラインからJavaのクラスを起動します。マシン上で1つ起動しておくJava仮想マシン部分と、コマンドを要求するリクエストエントリー部分からなります。両者はソケットを介して通信します。


リリースパッケージ

Mercury-0.2

2003年8月17日

配布形態 配布ファイル名 備考
バイナリ配布 mercury-0.2.tar.gz リクエストエントリ部はWin32版のみ
ソース配布 mercury-0.2-src.tar.gz

jcl.exeがもしかするとWindows95/98/Me系では動作しないかもしれません。使用しているACEライブラリのドキュメントを見ると95系で動作するためには今回使用していないデファインが1つ必要らしいのです。

Mercury-0.1-2

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仮想マシン部

Java仮想マシン部は、以下の4つのJavaクラスから構成されます。

Main.class
mainメソッドを持つ
ListenerThread.class
ソケット(ポート2345)を開き、リクエストを待つ。リクエストが来たら、CommandDispatcher.classに委ねる。
CommandDispatcher.class
コマンドを解析し、実行する。
MyURLClassLoader.class
URLClassLoaderを拡張したもの。検索対象パスを後で外部から追加できるように変更している。

通信インタフェース

ソケットを使用します。デフォルトはポート番号2345を使用します。コマンドラインからポート番号を指定可能です。リクエストの書式は以下のとおりです。

command + {args}* + CR + LF
command: [A-Z]
args: [^ ][^ ]*

本バージョンで用意しているリクエストは次の2つです。

  1. クラスファイルの検索パス追加
  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仮想マシン部へ通知します。コマンドラインオプションには、ソケットで送るリクエスト文字列をそのまま記述します。

ACEライブラリの使用

当初、Windows用リクエストエントリー部はWinSockを使い、Linux用リクエストエントリー部はBSD Socketを使っていました。同じロジックを実装するのに、2つのソースを書いて保守する必要がありました。これに新たなOSを加えるのは非常に面倒です。また、ソケットAPIはC言語のAPIで低レベルな記述を要求されます。そこで、OSの違いをラップした上にC++クラスライブラリとしてソケットAPIを提供するACEを使用することにしました。

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)メンバ関数で行えます。

GCCでのコンパイル
mercury$ g++ -I/usr/local/include -L/usr/local/lib/ace -lACE -o jcl jcl.cpp
mercury$ 

使用方法

以下、UNIXシェル上での操作で例示していますが、Windows上のDOSプロンプト上での操作でも同じです。

Java仮想マシン部の起動

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

改善

起動したクラスがexitすると、Java仮想マシン部も終了してしまう

起動したクラスが終了時にSystem.exit()を呼んでしまうと、Java仮想マシン部自身も終了してしまいます。これはなんとか防ぎたいものです。そこで、セキュリティマネージャとアクセス権の設定によってSystem.exit()を回避します。

jcl.policy
grant {
    permission java.lang.RuntimePermission "createClassLoader"; // 1
    permission java.io.FilePermission "<<ALL FILES>>", "read";  // 2
    permission java.net.SocketPermission "localhost", "accept, listen"; // 3
};
  1. URLClassLoaderを生成するのに必要なアクセス権
  2. URLClassLoaderを使ってファイルシステム上からクラスファイルを読み込む際に必要なアクセス権
  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秒


ToDo

Java高速起動ツール開発のToDoです。要望がありましたら追加いたします。

反映済み

Mercury-0.2

Mercury-0.1-2

Mercury-0.1-1


バグ

2003.08.17-01 <Mercury-0.1-2>
クラスファイル検索パスに、ディレクトリを指定したが末尾に'/'を付け忘れてもエラーや警告にはならなかった。<Mercury-0.2で修正>
2003.02.21-01 <Mercury-0.1-1>
Mercury起動後、CコマンドでURLを設定せずにいきなりRコマンドでクラスを実行しようとするとNullPointerExceptionガ発生する。<Mercury-0.1-2で修正>

This page is written by Toru TAKAHASHI.(torutk@02.246.ne.jp)