Java仮想マシンの基本原理とプロセスを理解すれば、JVMの60%をマスターできます。

Java仮想マシンの基本原理とプロセスを理解すれば、JVMの60%をマスターできます。

Java ユーザーとしては、JVM のアーキテクチャを習得することも必要です。

[[323342]]

Java について話すとき、人々が最初に思い浮かべるのは Java プログラミング言語です。しかし、実際には、Java は、Java プログラミング言語、Java クラス ファイル形式、Java 仮想マシン、および Java アプリケーション プログラム インターフェイス (Java API) の 4 つの側面から構成されるテクノロジです。それらの関係は次の図に示されています。

ランタイム環境は Java プラットフォームを表します。開発者は Java コード (.java ファイル) を記述し、それをバイトコード (.class ファイル) にコンパイルします。次にバイトコードがメモリにロードされます。バイトコードが仮想マシンに入ると、インタープリタによって解釈されて実行されるか、ジャストインタイム コード ジェネレータによって選択的にマシン コードに変換されます。

Java プラットフォームは、Java 仮想マシンと Java アプリケーション プログラミング インターフェイスによって構築され、Java 言語はこのプラットフォームに入るためのチャネルです。 Java 言語で記述およびコンパイルされたプログラムは、このプラットフォーム上で実行できます。このプラットフォームの構造を下図に示します。

Java プラットフォームの構造では、Java 仮想マシン (JVM) が中核にあり、基盤となるオペレーティング システムやハードウェアから独立したプログラムを実現するための鍵となっていることがわかります。その下には移行インターフェースがあり、これはアダプタと Java オペレーティング システムの 2 つの部分で構成されます。このうち、プラットフォームに依存する部分はアダプタと呼ばれます。 JVM は移行インターフェースを通じて特定のプラットフォームおよびオペレーティング システムに実装されます。 JVM の上には、Java の基本クラス ライブラリと拡張クラス ライブラリ、およびそれらの API があります。 Java API を使用して作成されたアプリケーション (アプリケーション) とアプレット (Java アプレット) は、Java 仮想マシン (JVM) によってプログラムとオペレーティング システムの分離が実現され、Java のプラットフォーム独立性が実現されるため、基盤となるプラットフォームを考慮せずに任意の Java プラットフォームで実行できます。

JVM のライフ サイクルには、Java プログラムを実行するという明確なタスクがあります。したがって、Java プログラムが起動されると、JVM のインスタンスが生成されます。プログラムが終了するとインスタンスは消えます。次に、JVM のアーキテクチャと動作プロセスという 2 つの側面から、JVM についてさらに詳しく調べます。

1. Java仮想マシンのアーキテクチャ

  • 各 JVM には 2 つのメカニズムがあります。

① クラスロードサブシステム: 適切な名前のクラスまたはインターフェースをロードする

②実行エンジン:ロードされたクラスまたはインターフェースに含まれる命令を実行する役割を担う

  • 各 JVM には次のものが含まれます。

メソッド領域、Java ヒープ、Java スタック、ネイティブ メソッド スタック、命令カウンタ、その他の暗黙のレジスタ

JVM の学習では、次の部分が最も重要だと私は考えています。

Javaコードのコンパイルと実行のプロセス全体

JVM メモリ管理とガベージコレクションのメカニズム

以下では、これらの部分を個別に説明します。

2. Javaコードのコンパイルと実行の全プロセス

前述したように、Java コードをコンパイルして実行するプロセス全体は、おおよそ次のようになります。開発者が Java コード (.java ファイル) を記述し、それがバイトコード (.class ファイル) にコンパイルされ、バイトコードがメモリにロードされます。バイトコードが仮想マシンに入ると、インタープリタによって解釈されて実行されるか、ジャストインタイム コード ジェネレータによって選択的にマシン コードに変換されて実行されます。

(1)Javaコードのコンパイルは、Javaソースコードコンパイラによって完了します。これは、JavaコードをJVMバイトコード(.classファイル)に変換するプロセスです。フローチャートは次のとおりです。

(2)Javaバイトコードの実行はJVM実行エンジンによって完了する。フローチャートは次のとおりです。

Java コードのコンパイルと実行のプロセス全体には、次の 3 つの重要なメカニズムが含まれます。

  • Javaソースコードコンパイルメカニズム
  • クラスローディングメカニズム
  • クラス実行メカニズム

(1)Javaソースコードコンパイル機構

Java ソースコードのコンパイルは、次の 3 つのプロセスで構成されます。

①解析して記号表に入力

②アノテーション処理

③意味解析とクラスファイルの生成

フローチャートは次のとおりです。

最終的に生成されるクラス ファイルは、次の部分で構成されます。

①構造情報:クラスファイル形式のバージョン番号、各パーツの数とサイズを含む

②メタデータ:Javaソースコード内の宣言や定数の情報に相当します。クラス/継承されたスーパークラス/実装されたインターフェースの宣言情報、ドメインとメソッドの宣言情報、定数プールが含まれます。

③メソッド情報:Javaソースコード内の文や式に対応する情報。バイトコード、例外ハンドラテーブル、評価スタックとローカル変数領域のサイズ、評価スタックタイプレコード、デバッグシンボル情報が含まれています。

(2)クラスローディング機構

JVM クラスのロードは、ClassLoader とそのサブクラスを通じて行われます。クラス階層と読み込み順序は次の図で表すことができます。

①Bootstrapクラスローダー

$JAVA_HOME の jre/lib/rt.jar 内のすべてのクラスをロードする役割を担います。これは C++ によって実装されており、ClassLoader のサブクラスではありません。

②拡張クラスローダー

$JAVA_HOME 内の jre/lib/*.jar または -Djava.ext.dirs で指定されたディレクトリ内の jar パッケージを含む、Java プラットフォームの拡張機能のいくつかの jar パッケージをロードする役割を担います。

③アプリクラスローダー

クラスパスで指定されたjarパッケージとディレクトリ内のクラスを記録する責任があります

④カスタムクラスローダー

これは、アプリケーションが独自のニーズに応じてカスタマイズする ClassLoader です。たとえば、tomcat と jboss は、j2ee 仕様に従って ClassLoader を実装します。ロードプロセス中に、まずクラスがロードされたかどうかを確認します。検査順序は、カスタム ClassLoader から BootStrap ClassLoader の順で下から上になります。クラスローダーがロードされている限り、このクラスはロードされているとみなされ、このクラスがすべてのクラスローダーによって 1 回だけロードされることが保証されます。読み込み順序は上から下です。つまり、上位層は層ごとにこのクラスを読み込もうとします。

(3)クラス執行メカニズム

JVM はスタックベースの仮想マシンです。 JVM は新しく作成されたスレッドごとにスタックを割り当てます。つまり、Java プログラムの場合、その操作はスタックの操作によって完了します。スタックはスレッドの状態をフレームに格納します。 JVM は、スタックに対してフレーム内のプッシュ操作とポップ操作の 2 つの操作のみを実行します。

JVM がクラス バイトコードを実行してスレッドを作成すると、プログラム カウンター (PC) とスタックが生成されます。プログラム カウンターには、メソッド内で実行される次の命令のオフセットが格納され、スタックにはスタック フレームが格納されます。各スタック フレームは各メソッドの各呼び出しに対応し、スタック フレームはローカル変数領域とオペランド スタックの 2 つの部分で構成されます。ローカル変数領域は、メソッド内のローカル変数とパラメータを格納するために使用され、オペランド スタックは、メソッドの実行中に生成された中間結果を格納するために使用されます。スタックの構造を次の図に示します。

3. JVM メモリ管理とガベージコレクションのメカニズム

JVM のメモリ構造は、メソッド領域 (メソッド)、スタック メモリ (スタック)、ヒープ メモリ (ヒープ)、ローカル メソッド スタック (Java の jni 呼び出し) に分かれており、構造図は次のとおりです。

(1)ヒープメモリ

new によって作成されたオブジェクトのすべてのメモリはヒープ内に割り当てられ、そのサイズは -Xmx と -Xms によって制御できます。

オペレーティング システムには、空きメモリ アドレスを記録するリンク リストがあります。システムはプログラムから要求を受け取ると、リンク リストを走査して、要求されたスペースよりも大きいスペースを持つ最初のヒープ ノードを見つけます。次に、空きノードのリンク リストからノードを削除し、ノードのスペースをプログラムに割り当てます。さらに、ほとんどのシステムでは、この割り当てのサイズがこのメモリ空間の最初のアドレスに記録されるため、コード内の delete ステートメントはメモリ空間を正しく解放できます。ただし、見つかったヒープ ノードのサイズは必ずしも要求されたサイズと正確に一致するとは限らないため、システムは余分な部分を自動的にフリー リストに戻します。この時点で new によって割り当てられるメモリは、一般的に速度が遅く、メモリの断片化が発生しやすくなりますが、使用するには最も便利です。さらに、WINDOWS では、VirtualAlloc を使用してメモリを割り当てるのが最善の方法です。ヒープやスタック内ではなく、プロセスのアドレス空間にメモリの一部を直接予約します。この方法は最も使い勝手が悪いですが、高速で柔軟性も最も高い方法です。ヒープ メモリは、上位アドレスまで拡張されたデータ構造であり、不連続なメモリ領域です。システムは空きメモリ アドレスを格納するためにリンク リストを使用するため、空きメモリ アドレスは自然に不連続になり、リンク リストのトラバース方向は低いアドレスから高いアドレスの方向になります。ヒープのサイズは、コンピュータ システムで使用可能な仮想メモリによって制限されます。これは、ヒープによって取得されるスペースがより柔軟で大きいことを示しています。

(2)スタックメモリ

Windows では、スタックは下位アドレスまで拡張されたデータ構造であり、連続したメモリ領域です。この文は、スタックの最上位のアドレスとスタックの最大容量がシステムによって事前に決定されていることを意味します。 WINDOWS では、スタックのサイズは固定されています (コンパイル時に決定される定数)。要求されたスペースがスタックの残りのスペースを超える場合、オーバーフロー プロンプトが表示されます。したがって、スタックから使用できるスペースは少なくなります。スタック上の残りのスペースが要求されたスペースよりも大きい限り、システムはプログラムにメモリを提供します。そうでない場合、スタック オーバーフローを示す例外が報告されます。システムによって自動的に割り当てられ、より高速になります。しかし、プログラマーはそれを制御できません。ヒープ メモリとスタック メモリについて説明する必要があります。

基本データ型はスタック空間に直接割り当てられ、メソッドの仮パラメータはスタック空間に直接割り当てられ、メソッド呼び出しが完了した後にスタック空間から回復されます。参照データ型は、スタック空間にアドレス空間を割り当て、ヒープ空間にオブジェクトのクラス変数を割り当てる new を使用して作成する必要があります。メソッドの参照パラメータはスタック空間にアドレス空間を割り当て、ヒープ空間のオブジェクト領域を指します。メソッド呼び出しが完了すると、スタック スペースから再利用されます。ローカル変数が新しく作成されると、スタック領域とヒープ領域にスペースが割り当てられます。ローカル変数のライフサイクルが終了すると、スタック領域はすぐに再利用され、ヒープ領域は GC による再利用を待機します。メソッドを呼び出すときに渡されるリテラル パラメーターは、最初にスタック スペースに割り当てられ、メソッド呼び出しが完了した後にスタック スペースから回復されます。文字列定数と静的は DATA 領域に割り当てられ、これはヒープ領域に割り当てられます。配列は、配列名としてスタック スペースに割り当てられ、配列の実際のサイズとしてヒープ スペースに割り当てられます。

のように:

(3)ネイティブメソッドスタック(JavaでのJNI呼び出し)

ネイティブ メソッドの実行をサポートし、各ネイティブ メソッド呼び出しのステータスを保存するために使用されます。ネイティブ メソッド インターフェイスの場合、JVM の実装では必ずしもそのサポートは必要なく、サポートされていない場合もあります。 Sun は移植性を考慮して Java Native Interface (JNI) を実装しました。もちろん、Sun の JNI に代わる他のネイティブ インターフェイスを設計することもできます。ただし、これらの設計と実装は比較的複雑な問題であり、ガベージ コレクターがネイティブ メソッドによって呼び出されているオブジェクトを解放しないようにする必要があります。

(4)方法領域(方法)

メソッド コード (コンパイルされた Java コード) とシンボル テーブルを保持します。ロードされるクラス情報、静的変数、最終型定数、プロパティ、メソッド情報を格納します。 JVM は、メソッド領域を格納するために Permanent Generation を使用します。最小値と最大値は、-XX:PermSize と -XX:MaxPermSize を通じて指定できます。

ガベージコレクションの仕組み

アプリケーションによって作成されたすべてのオブジェクトはヒープ内に集められます。 JVM には、new、newarray、anewarray、multianewarray などの対応する命令もあります。ただし、C++ には delete や free のような領域を解放するための命令はありません。 Java のすべてのリリースは GC によって行われます。メモリのリサイクルに加えて、GC のもう 1 つの重要なタスクはメモリの圧縮です。これは他の言語でも同様の実装があります。 C++ と比較すると、使いやすいだけでなく、セキュリティも向上しています。もちろん、パフォーマンス上の大きな問題など、デメリットもあります。 4. Java仮想マシンの動作プロセスの例

上記では、仮想マシンのさまざまな部分について詳しく説明しています。次の例では、その動作プロセスを分析します。

仮想マシンは、指定されたクラスの main メソッドを呼び出して起動し、文字列配列パラメータを main に渡します。これにより、指定されたクラスがロードされ、クラスで使用される他の型がリンクされて初期化されます。たとえば、次のプログラムの場合:

コンパイル後、コマンドラインモードで次のように入力します: java HelloApp run virtual machine

Java 仮想マシンは、HelloApp の main メソッドを呼び出して、3 つの文字列「run」、「virtual」、および「machine」を含む配列を main に渡すことによって起動されます。ここで、HelloApp を実行するときに仮想マシンが実行する可能性のある手順の概要を説明します。

HelloApp クラスのメイン メソッドの実行を開始し、クラスがロードされていない (つまり、仮想マシンには現在クラスのバイナリ表現が含まれていない) ことが検出されるため、仮想マシンは ClassLoader を使用してそのようなバイナリ表現を見つけようとします。このプロセスが失敗すると、例外がスローされます。クラスがロードされた後、メイン メソッドが呼び出される前に、HelloApp クラスを他の型とリンクして初期化する必要があります。リンクは、検証、準備、解決の 3 つの段階で構成されます。検証では、ロードされたメイン クラスのシンボルとセマンティクスがチェックされます。準備では、クラスまたはインターフェースの静的フィールドを作成し、これらのフィールドを標準のデフォルト値に初期化します。解決は、メイン クラスの他のクラスまたはインターフェースへのシンボリック参照をチェックする役割を担います。このステップではオプションです。クラスの初期化は、クラスで宣言された静的フィールドの静的初期化関数と初期化コンストラクターの実行です。クラスを初期化する前に、その親クラスを初期化する必要があります。全体のプロセスは次のとおりです。

<<:  Java仮想マシンオブジェクトの生存判定とガベージコレクションアルゴリズム

>>:  ガートナー:アリババクラウドは世界第3位、アジア太平洋地域で第1位となり、シェアが拡大してアマゾンの市場シェアを圧迫している

推薦する

Google が好む 17 種類のコンテンツ: インタビュー、ニュース、ケーススタディ/調査など

1. インタビューGoogle は質の高いコンテンツを作成する人々を尊重します。もっと簡単な方法は、...

Alibaba Cloudの技術専門家が世界最大のオープンソースコミュニティのApacheメンバーに選出

最近、世界最大のオープンソースコミュニティであるApache Software Foundation...

2015 年の最新戦略: 予算ゼロで Android サードパーティ チャネルを構築するには?

はじめに:ご存知のとおり、国内のAndroidチャンネルは主にサードパーティ製であり、どの程度のボリ...

世界は将来のリスクへの対応力向上のためデジタル政府構築を強化している

COVID-19パンデミックにより、失業率が急上昇し、地域の多くの国々が大きな圧力にさらされている。...

ユーザーが10秒以内にウェブサイトを離れる25の理由、まずは最悪のものから

人々があなたのページを訪問した後すぐに「戻る」ボタンを押すのはなぜでしょうか? 人々はなぜそんなに早...

AI エッジコンピューティングとは何ですか?エッジコンピューティングの利点は何ですか?

近年、人工知能の導入が大幅に増加しています。ビジネス データ、IoT アプリケーション、そして以前よ...

インタビューエピソード11: SEOテクノロジーを活用して利益を最大化し、ビジネスを立ち上げる方法

インタビューゲスト:馬海斌ゲスト情報: SEO の専門家、別名 Feather Teacher面接日...

クラウドネイティブテクノロジーが5Gモバイルネットワークに与える影響

[[421463]]多くの通信サービスプロバイダー (CSP) は、ネットワーク インフラストラクチ...

hostdare: 20% オフ、ロサンゼルス VPS、年間 20 ドル、512M メモリ/1 コア/10g NVMe/500g 帯域幅

Hostdare は、従来の国際 BGP 回線を使用する Quadranet のロサンゼルス データ...

元斉森林のブランドマーケティングを説明する12,000語

飲料業界の専門家とコミュニケーションをとる過程で、私たちは一連の興味深い視点を観察しました。巨大飲料...

「知会杯」2019年全国大学金融技術イノベーションコンテスト授賞式および大学金融技術サミットフォーラムが成功裏に終了

2019年12月13日、「知会杯」2019年度全国大学フィンテックイノベーションコンテスト表彰式お...

コンテンツタイトルの需要は、クリックを誘引するマーケティングよりもはるかに価値があります。

百度にはクリック原則があり、クリックによってキーワードのランキングが向上することは誰もが知っているの...

vpslot: ドバイ VPS、月額 16 ドルから、帯域幅 1Gbps、中東に最適

主に米国(シカゴ)と中東のドバイVPSを運営しています。独立サーバーは米国シカゴとニューヨークにもデ...

コンテンツマーケティングはブランド構築に役立ち、それがウェブサイト開発への道となる

コンテンツ マーケティングの目標は、潜在顧客との親しみと信頼を築くことであると多くの人が知っていると...