Java仮想機械
先週はJavaのヴァーチャルマシンの話をしていた
Javaの
バイトコード
普通の
機械語とすごく違うわけではない
最近は下火だけれど
Javaの
バイトコードを直接実行するプロセッサを作っていた
今はどっかのメーカーに行けばあるかもしれないけれど
大々的には売れていないはず
最初は携帯電話などに売り込もうとしたのだけれど
何が悪かったのかわからないけれど
ビジネス的には失敗している
ただし
バイトコードの全部を実際に実行できるわけではない
メソッド呼び出しなど、
できなくはないのだろうけれどあまり現実的ではない
そこらへんはハードウェアではやっていなかったはず
割り込みが発生してどっか飛んでいく
携帯電話のチップはコストパフォーマンスが激しい
携帯電話のプログラムは全部が
Javaというわけではない
そういうのもひっくるめて安く効率よく開発できないといけない
Javaだけが動いてもねえ…という感じかも
元々の目論見は全部
Javaでやればいいんだ、ということだったのだろうけど
しかしサンは最近もまだまだ組み込みに活路を見出そうとしている
Javaの
機械語を素直に実行するなら
インタプリタを作ることになる
そうすると
バイトコードは小さくなるけど実行性能はでない
普通の
機械語だったら1サイクルで1命令
インタプリタだと100サイクルくらいかかるかもしれない
単純に100倍遅くなる
Javaが登場してからわりとすぐ、
まともな速度で動かす技術(Dynamic compilation)がでてきた
Java以前からあった技術
Smalltalkとか
IBMが今の
Javaの役目を
Smalltalkで置き換えようという時期も一瞬あった
要するに
COBOLの役目を置き換えたかった
結局
COBOLは
Javaに置き換えられつつある
しかし
IBMは
Smalltalkの会社を買収してしまったのでどうしよう?
レイオフ?
結局
Smalltalkで
Javaの開発環境とか作った
割と良く出来ていたのでそれを
Javaで書き換えて
Eclipseができた
という関連が
Javaと
Smalltalkにはある
サンは
Smalltalkの
コンパイラを作っていたエンジニアを引き抜いて
Dynamic compilationの技術を取り入れた
実行中に
バイトコードをネイティブコード(
x86とか)に変換(
コンパイル)する
コンパイルという言葉は普通人間が読めるプログラムから
機械語に変換することを言うけれど
広く捉えれば
機械語から
機械語へも
コンパイル
Just-in-time
ロードした後、実行が始まってから
コンパイルを行う
hotspot
良く実行されているところ
良く使われる回路が熱くなるから?
ともかく熱くなっている
メソッドをhotspotと呼ぶ
無制限に
コンパイル時間をかけられない
コンパイル時間を短くする必要がある
普通の
コンパイルは編集した直後にやるのですごく時間がかかっても許される
最近の人はせっかちだからあまり許されないかもしれないが…
Eclipseを使っていると編集しているそばから
コンパイルしている
すごく
コンパイル時間が体感で短くなる
まあ今の人でも2、3秒なら許されるのかな
ネイティブコードに変換する目的は
Javaを早くするためにある
早くするために
コンパイルをする
しかし
JITなので
コンパイル時間は実行時間に含まれている
コンパイルに時間をかけすぎるとかえって遅くなってしまう
いかにして
コンパイル時間を短くするか
全部を
コンパイルしない
何度も実行される部分だけ
コンパイルする
インタプリタ コンパイル
ある
メソッドの実行時間 3秒 1秒
+5秒(
コンパイル時間)
実行回数1回 3 6
実行回数5回 15 5+1*5=10
良く実行される
メソッドやループの内側を探し出して
コンパイルすると
多少
コンパイルに時間がかかってもトータルでも短くなることが期待される
しかし
コンパイルの結果はディスクに保存しなければいけない
メモリのオーバーヘッドも考えなければいけない
仮想記憶を使っている時など…
コンパイルにはいろいろ程度がある
最適化を強力にかけるかそうでないか
普通は時間をかけてより強力な
機械語を出力することが多いが
あえて最適化をしないという戦略もある
まず軽く
コンパイル それでも
インタプリタよりは早いでしょ
何度も実行されたら最適化をかける
プログラムの殆どの部分は軽く
コンパイルをかけていおいて
ここは最適化を頑張った方がいいぞというところは時間をかけて最適化をする
インタプリタをほとんど持っていなくて
最初に軽く
コンパイルをかけるようなものもある
JITではないものはAhead-of-time compilationと呼ぶ
しかし一般的な
Javaの仮想機械ではAoTは使われていない
教科書的な理由は、実行中に
コンパイルした方がよく最適化されたコードが出てくる
Dynamic compileの利点
良く使われてかつ短い
メソッドをインライン化
分岐予測、最近はハードウェアでやるのでソフトウェアだとどうなのかちょっとわからない
JavaというのはDynamicにプログラムをロードうすることができるので
…という話は後にしましょう
ではAhead-of-timeの欠点は?
分岐予測とかは普通の
コンパイラでもプロファイルを利用すれば大丈夫
AoTが使われないのは性能云々ではなく
Javaの使われ方の問題
ブラウザの中で
Javaの
VMを動かしていてDLしてきたものを実行する、など
Ahead-of-timeはサーバサイドでは悪くない
クライアント側で使おうとすると起動するたびに
コンパイルするのではたまらない
対話性が著しく悪い
開発する側も2回も
コンパイルするのが面倒
また、セキュリティ上の立場からもよくない
Officeとかも起動した直後はなんだか遅い
おそらくAoTを行っているのではないか
Javaの
VMと同じような技術を使っている
Escape Analysis
x86とかのハードウェアで直接実行される
機械語に変換すればまあ早くなる
しかし
Java言語特有の遅さというものもある
JavaはCと違って高級すぎるので単純に
コンパイルしただけでは
あんまり早くは動かない
Cでも経験のない人が書いたら遅くなってしまうかもしれない
Javaだと経験のある人が頑張って書いてもあまり早くは動かない
メモリ管理
Javaの場合は全てヒープ領域に割り当てる
簡単に言えばCで
mallocを使って割り付けるようなもの
実行中に空いているところを探して割り付ける 動的に割り付ける
ある変数はずっと使われ続けるわけではない
使い終わったところは違う変数のために再利用
ここは使われている
ここは使われていない
そういった情報を管理する
動的に割り付けるのは結構大変
そんなに早いわけではない
メモリも飛び飛びになってしまうし
Cっていうのは、
プログラマは偉い、何でも知っている、
というのが前提の言語なので
スタック領域にメモリを割り付けるという方法も選べる
スタック領域とは
メソッド呼び出しの際にまとめて確保される領域
メソッドは最後に呼び出した
メソッドが必ず最初に終わる
メソッドが終わったらまとめて解放する
これなら
フラグメンテーションが発生しないしすごく高速に管理できる
続きは来週