(0)目次&概説
(1) 記事の目的
(2) Javaのアーキテクチャ概要・概観
(3) JVMのアーキテクチャ概要
(3-1) JVMの概観
(3-2) JVMの主要サブシステム1:Class Loader
(3-3) JVMの主要サブシステム2:Runtime Data Area
(3-3-1) Method Area(メソッド領域)
(3-3-2) Heap Area(ヒープ領域)
(3-3-3) Stack Area(スタック領域)
(3-3-4) Native Stack(ネイティブスタック)
(3-3-5) Program Counter Register(PCレジスター)
(3-4) JVMの主要サブシステム3:Execution Engine
(3-4-1) JIT Compiler(JITコンパイラ)
(3-4-2) Garbage Collector(ガーベジコレクタ)
(1) 記事の目的
長くなったので、こちら(Javaのアーキテクチャ概要)の記事にて記載。
(2) Javaのアーキテクチャ概要・概観
長くなったので、こちら(Javaのアーキテクチャ概要)の記事にて記載。
(3) JVMのアーキテクチャ概要
前回の記事「Javaのアーキテクチャ概要」では、プログラムのコンパイル~実行までの大まかな流れやJDK・JRE・JVMの定義について確認しました。その続きで、今回はバイトコードを解釈・実行する、JREのエンジン(心臓)部分である「JVM」について、もう少し掘り下げて見ていきたいと思います。
(3-1) JVMの概観
VMの主な役割としては4つあります。
①ソースコードのロード
②ソースコードの検証
③ソースコードの実行
④PGメモリの最適化
⇒Javaが登場する前はメモリは各プログラマが個別に管理していました。しかしJavaではJVMがメモリの管理を行ってくれます。
(※Heap領域やStack領域のチューニングや、Garbage Collection)
上記の役割を下記のサブシステムが分担して行っています。
①Class Loader Subsystem(クラスローダー)
②Runtime Data Area(ランタイムデータエリア)
③Execute Engine(実行エンジン)
全体像としては下図のようになります。
(図311)JVMのアーキテクチャ概要
(3-2) JVMの主要サブシステム1:Class Loader
・JVMのサブシステムの一つで、クラスファイル(.class)のロードに使われます。
・Javaプログラムを実行すると、まず最初にこのClass Loaderが動作します。
(3-3) JVMの主要サブシステム2:Runtime Data Area
JVMの実行時のメモリ領域は大きく分けて2種類に分類ができます。
①スレッド毎の領域
スレッド毎に一意なメモリを割り当てられているケースです。これらのメモリ領域はスレッドの開始時に初期化され、スレッドが完了すると破棄されます。
②共有の領域
メモリ領域が共有で全てのスレッドからアクセス可能なケースです。これらのメモリ領域はJVMの起動と同時に初期化され、JVMのシャットダウン時に破棄されます。
(3-3-1) Method Area(メソッド領域)
・JVMメモリ上のデータ領域で、クラスに関するデータが保存されます。
・クラス名やスーパークラス名、static変数やstaticメソッド、インスタンスメソッド等が保存されます
・Method AreaはJVMに対して1つのみ存在する共有のリソースである。
(3-3-2) Heap Area(ヒープ領域)
・JVMの起動時に確保されるメモリ領域のうち、インスタンスのために割り当てられた領域です。
・クラスから生成されたインスタンスと、そのメンバ変数がヒープ領域に格納されています。
・ヒープ領域の大きさはアプリケーション実行の中で増減します(調整される)。
・ヒープ領域の内部には更に「String Pool」という領域があり、Stringの固定値が管理されています。
・JVMに対して1つのみ存在する共有リソースで各スレッドからアクセスが可能(スレッドセーフでない)
(3-3-3) Stack Area(スタック領域)
■概要
・JVMで確保されるメモリ領域のうち、ローカル変数等のために割り当てられた領域です。
・各スレッド毎にJVMが生成するランタイムスタックがここに格納されます。
・そのスタックのブロック1つ1つを「スタックフレーム」(Activation Recordの実装)と呼びます。
・メソッド呼び出し毎に「スタックフレーム」が作られ、その際に動的リンク(Dynamic Linkage)が行われます
・Dynamic Linkageとはクラスを動的にロードする際に、既存のクラスとの互換性があるか?を検証する機能のことです。
・スレッドが強制終了すると、実行時のスタックはJVMにより破壊されます。
■スタックフレーム3つのサブエンティティ
①Local Variable Array
ローカル変数とその値を保持しています。
②Operand Stack
中間処理のためのワーク領域として利用されます
③Frame Data
・シンボリック参照(クラス参照やメソッド参照やフィールド参照など)を含んでいます。
・例外が発生した際にcatchブロックの情報を返却するための、例外テーブルへの参照を保持。
■スタックサイズ
・スタックのサイズは2種類、固定と変動があります。変動は実行時に動的にサイズを拡張できます。
・エラー「StackOverflowError」はスタックが固定で、実行時にサイズが不足した場合に発生します。
・エラー「OutOfMemoryError」はスタックが変動で、拡張時にメモリ不足で拡張できない場合に発生します。
(3-3-4) Native Stack(ネイティブスタック)
・スレッド単位でNative Stack領域が作成されます
(3-3-5) Program Counter Register(PCレジスター)
・各スレッドにおいて現在実行されている、その瞬間に実行されている箇所をトレースします。
・PC Registersはスレッド毎に生成され、各スレッド単位でトレースを行っています。
(3-4) JVMの主要サブシステム3:Execution Engine
(3-4-1) JIT Compiler(JITコンパイラ)
・Just in time complierの略で、実行時にバイトコードを機械語に変換する事でJavaアプリケーションのパフォーマンスを改善に寄与します(※インタプリタの速度面で不利な点を補う)。
・メソッドがコンパイルされると、JVMは実行の直前にそのバイトコードを機械語に変換します(直前なのでJust in timeという名称)。
・その中で同一のコードが繰り返し出現する場合は、JITコンパイラを用いてバイトコード全体を機械語に一括変換します(少しずつ見るより早い)。
・JVMのインタプリタがバイトコードを変換する速度に比べて、JITコンパイラの方が速くオーバヘッドが少ないため、Java言語の実行速度の高速化にも寄与しています。
(3-4-2) Garbage Collector(ガーベジコレクタ)
・使っていない領域を集めてガーベジコレクションを行う部品です。
・JVMのヒープ領域にある全てのオブジェクトを追跡し、不要なものを取り除きます。
・主に「Mark」と「Sweep」と呼ばれる2つのステップにより実行されます。
・Mark:ガーベジコレクタが使用されているメモリとそうでないメモリを判別する場所です(マーキングから命名したのでしょうか。
・Sweep:「Mark」にて不要と判断されたオブジェクトを取り除きます。