Java の場合 (1/2)


お次は、Java 言語の場合。皆さんは、で Java 言語を学び始めていることでしょう。

Java の場合、機械語命令の代りに、仮想機械(virtual machine)語であるところの bytecodeというものを使います。 で、CPU や OS を選ばず、同じプログラムがどこでも走ると言われています。 だから、Windows 端末でもサーバマシンでもどこでも同じプログラムが動き、 ネットワーク世界に向いているなんて言われたりしたわけです。

とりあえずは C 言語を振り返りましょう。

C 言語ソースコード (with マクロ)
↓ マクロ展開
C 言語 (マクロ展開済)
↓ コンパイル
アセンブリコード
↓ アセンブル
オブジェクトコード
↓ リンク
実行コード
で、この中で機種依存でないのは「良くても」 C言語 (マクロ展開済)までです。 アセンブリから下は異なります。「良くても」っていったのは、C言語には標準ライブラリがあまり整備 されていないため、すこし凝ったことをしようとすると、OS 依存の関数群を使うことになります。 ということは、MS-Windows 用につくった C言語ソースを Linux のところにもっていっても、 コンパイルできないわけです。

じゃあ、Java の方はどうなっているかというと、

Java 言語ソースコード (XXX.java)
↓ コンパイル javac XXX.java
クラスファイル(仮想機械語, bytecode) XXX.class
↓ ロード
仮想機械(VM)上で interpretive/jit 実行 java XXX
というわけです。リンク操作はロードというところに入ってしまいましたし、 コンパイルとアセンブルは一体化しています。

で、いわゆるオブジェクトファイルに相当するクラスファイルは、機種非依存です。 標準API(Application Programming Interface)といわれるライブラリもOSによらず統一されています。 というわけで、プログラムをどこに持っていっても動く(write once, run everywhere)と言うわけです。

とはいっても、最終的にプログラムを実行するためにはCPUが機械語で動いているわけです。 誰がその任にあたっているかというと、VM 君です。 VM のつくりには大きく 2 種類あります。解釈(interpritive)実行JIT(Just-In-Time) Compilerによる 実行です。 とってもおおざっぱにいうと、 解釈実行というのは、各bytecode命令に相当するルーチンを準備しておいて、 bytecode 命令を取り出しては、各ルーチンを実行するという感じです。 一方で、JIT Compiler というのは、bytecode 命令列を機械語に変換してしまってから 実行しようというものです。 なぜ JIT(Just-In-Time) というかというと、プログラムが実行される都度、その場で compile をおこなう からです。 JIT コンパイラによっては、変換に要する時間を短縮するため、 良く使いそうなところだけコンパイルするという技術をつかうものも多いです。 さらに賢い JIT の場合、一度走らせてプログラムの実行の傾向を調べておいてから、 その情報を元に最適化(実行効率をあげるためのチューニング)をおこなうものもあります。

皆さんがつかっている VM がどんなものか知りたければ、

kamada@cygwin% java -version
java version "1.3.0_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0_02)
Java HotSpot(TM) Client VM (build 1.3.0_02, mixed mode)
とやることで、HotSpot Engine といわれる JIT つき VM が起動していることがわかります。 ついでに、クラスファイルの中身を知りたい場合は、以下のようにすることで、 中身を知ることもできます。
kamada@cygwin% javap -c Hello
Compiled from Hello.java
....続きはこちら

2001.9.25/ Tomio KAMADA: kamada@cs.kobe-u.ac.jp