10年の経験を持つ建築家がJVMの動作原理を解説

10年の経験を持つ建築家がJVMの動作原理を解説

Java 開発を行うほとんどの人は JVM という用語を知っていますが、JVM は実際の単純な開発にはあまり関係がないため、一般的には 1 年か 2 年働いた後 (もちろん、学習が好きでパフォーマンスの最適化を専門とする人は除きます)、JVM とは何か、どのように機能するかを学習して理解できる人はほとんどいません。特にJava開発者として始めたばかり、あるいは始めたばかりの人にとっては、これを真剣に理解し学ぶことが非常に必要だと個人的には思います。 JVM は Java の基礎です。

[[312896]]

1. JVM分析

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

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

Java プラットフォームは、Java 仮想マシンと Java アプリケーション プログラミング インターフェイスによって構築され、Java 言語はこのプラットフォームに入るためのチャネルです。 Java 言語で記述およびコンパイルされたプログラムは、このプラットフォーム上で実行できます。このプラットフォームの構造を下図に示します。ランタイム環境は Java プラットフォームを表します。開発者は Java コード (.java ファイル) を記述し、それをバイトコード (.class ファイル) にコンパイルします。次にバイトコードがメモリにロードされます。バイトコードが仮想マシンに入ると、インタープリタによって解釈されて実行されるか、ジャストインタイム コード ジェネレータによって選択的にマシン コードに変換されます。

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

次に、JVM の基本概念と操作プロセスという 2 つの側面から詳細に学習します。

2. JVMの基本概念

(1)基本概念:

JVM は、バイトコード命令セット、レジスター セット、スタック、ガベージ コレクター、ヒープ、およびストレージ メソッド ドメインで構成され、Java コードを実行できる仮想コンピューターです。 JVM はオペレーティング システム上で実行され、ハードウェアと直接やり取りすることはありません。

(2)操作手順:

Java ソース ファイルはコンパイラを通じて対応する .Class ファイル、つまりバイトコード ファイルを生成でき、バイトコード ファイルは Java 仮想マシンのインタープリタを通じて特定のマシン上でマシン コードにコンパイルされることは周知の事実です。

つまり、次のようになります。

① Javaソースファイル -> コンパイラ -> バイトコードファイル

② バイトコードファイル -> JVM -> マシンコード

各プラットフォームのインタープリターは異なりますが、実装される仮想マシンは同じです。これが、Java がクロスプラットフォームである理由です。プログラムの実行が開始されると、仮想マシンのインスタンス化が開始されます。複数のプログラムを起動すると、複数の仮想マシン インスタンスが存在します。プログラムが終了または閉じられると、仮想マシン インスタンスは消え、複数の仮想マシン インスタンス間でデータを共有できなくなります。

(3)JVMの3つの種類:

①太陽からのホットスポット

② BEAのJRockit

③ IBMのJ9 JVM;

JDK1.7 以前では Sun の HotSpot を使用していましたが、Sun と BEA の両方が Oracle に買収されたため、JDK1.8 では Sun の HotSpot と BEA の JRockit のエッセンスを使用して JDK1.8 の JVM を形成します。

3. JVMアーキテクチャ

(1)クラスローダー

.class ファイルの読み込みを担当します。クラスファイルはファイルの先頭に特定のファイルマーカーを持っており、ClassLoader がクラスファイルのロードなどを担当します。実行できるかどうかは実行エンジンによって判断されます。

①バイナリクラスファイルを見つけてインポートする

②インポートしたクラスの正しさを確認する

③ クラスの初期メモリを割り当てる

④ シンボル参照の解決を支援します。

(2)ネイティブインターフェース:

ネイティブ インターフェイスの役割は、さまざまなプログラミング言語を統合して Java で使用することです。当初の目的は、C/C++ プログラムを統合することでした。 Java が誕生したとき、C/C++ が蔓延していました。足がかりを得るためには、C/C++ プログラムを呼び出す必要がありました。そのため、ネイティブとしてマークされたコードを処理するために、メモリ内に特別な領域が開かれました。具体的なアプローチは、ネイティブ メソッドをネイティブ メソッド スタックに登録し、実行エンジンで実行するときにネイティブ ライブラリをロードすることです。

現在、Java プログラムでプリンターを駆動したり、Java システムで生産設備を管理したりするなど、ハードウェア関連のアプリケーションでない限り、この方法はますます使用されなくなっています。エンタープライズ レベルのアプリケーションではすでに珍しいことです。

異種分野間の通信が非常に発達しているため、ソケット通信や Web サービスも利用できます。

(3)実行エンジン:実行エンジンは、ロードクラスのメソッド、つまりメソッドに含まれる命令を実行します。

(4)ランタイムデータ領域:

仮想マシン メモリまたは Jvm メモリは、Jvm に必要なオブジェクトや変数などを格納するために、コンピュータ メモリ全体にメモリの一部が割り当てられます。実行領域データは、メソッド領域、仮想マシン スタック、ローカル メソッド スタック、ヒープ、プログラム カウンターなど、多くの小さな領域に分割されます。

4. JVMデータ操作領域(スタック管理操作、ヒープ管理ストレージ)の詳細説明:

注: JVM のチューニングでは、主にヒープとメソッド領域の最適化が行われます。

(1)ネイティブメソッドスタック

具体的なアプローチは、ネイティブ メソッドをネイティブ メソッド スタックに登録し、実行エンジンの実行時にネイティブ ライブラリをロードすることです。

(2)PCレジスタプログラムカウンタ

各スレッドにはプログラム カウンターがあり、これはメソッド領域内のメソッド バイトコード (次に実行される命令コード) を指すポインターです。実行エンジンは次の命令を読み取ります。これはほとんど無視できるほど小さなメモリ空間です。

(3)方法領域

メソッド領域はすべてのスレッドで共有されます。すべてのフィールドとメソッドのバイトコード、およびコンストラクターやインターフェース コードなどの一部の特殊メソッドもここで定義されます。簡単に言えば、定義されたすべてのメソッドに関する情報は、共有領域に属するこの領域に保存されます。

静的変数 + 定数 + クラス情報 + 実行時定数プールはメソッド領域に格納され、インスタンス変数はヒープメモリに格納されます。

(4)スタック

①スタックとは何か?

スタック (スタック メモリとも呼ばれます) は、Java プログラムの実行を担当します。スレッドが作成されるときに作成されます。そのライフサイクルはスレッドのライフサイクルに従います。スレッドが終了すると、スタック メモリが解放されます。スタックにはガベージ コレクションの問題はありません。スレッドが終了すると、スタックは Over になります。ライフ サイクルはスレッドと一致しており、スレッド専用です。

基本型の変数とオブジェクト参照変数は、関数のスタック メモリに割り当てられます。

② スタックには何が格納されますか?

スタック フレームには主に次の 3 種類のデータが格納されます。

ローカル変数: メソッド内の入力および出力パラメータと変数。

オペランド スタック: スタックのポップとプッシュの操作を記録します。

フレーム データ: クラス ファイル、メソッドなどが含まれます。

③スタックの動作原理

スタック内のデータはスタック フレームの形式で存在します。スタック フレームは、メモリ ブロック、データ セット、メソッドおよびランタイム データに関するデータ セットです。メソッド A が呼び出されると、スタック フレーム F1 が生成され、スタックにプッシュされます。メソッド A はメソッド B を呼び出すため、スタック フレーム F2 もスタックにプッシュされます。メソッド B はメソッド C を呼び出すため、スタック フレーム F3 もスタックにプッシュされます... 実行が順番に完了すると、最初に F3 スタック フレームがポップアウトされ、次に F2 スタック フレームがポップアウトされ、最後に F1 スタック フレームがポップアウトされます。

「先入れ後出し」/「後入れ先出し」の原則に従ってください。

(5)ヒープ

ヒープ領域は JVM 内で最大です。アプリケーション オブジェクトとデータはこの領域に保存されます。この領域もスレッドによって共有され、GC の主なリサイクル領域となります。 JVM インスタンスにはヒープ クラス メモリが 1 つだけあり、ヒープ メモリのサイズは調整できます。クラス ローダーはクラス ファイルを読み取った後、エグゼキュータの実行を容易にするために、クラス、メソッド、定数変数をヒープ メモリに配置する必要があります。ヒープ メモリは 3 つの部分に分かれています。

①新入生エリア

新生児領域は、クラスが生まれ、成長し、消滅する領域です。クラスは生成され、適用され、最終的にガベージ コレクターによって収集され、ここでその有効期間が終了します。新しいエリアは、エデン スペースとサバイバー ペースの 2 つの部分に分かれています。すべてのクラスは、Eden スペースに新しく作成されます。サバイバー スペースには、サバイバー 0 スペースとサバイバー 1 スペースの 2 つがあります。 Eden のスペースが使い果たされ、プログラムがオブジェクトを再度作成する必要がある場合、JVM のガベージ コレクターは Eden でガベージ コレクション (マイナー GC) を実行し、Eden 内の残りのオブジェクトをサバイバー ゾーン 0 に移動します。サバイバー ゾーン 0 もいっぱいの場合、そのゾーンでガベージ コレクションが実行され、ゾーン 1 に移動されます。エリア 1 もいっぱいの場合はどうなるでしょうか。その後、退職エリアへ移動します。退避領域もいっぱいの場合は、この時点でメジャー GC (FullGCC) が生成され、退避領域のメモリがクリーンアップされます。フル GC を実行した後も、リタイアメント領域でオブジェクトを保存できないことが判明した場合、OOM 例外「OutOfMemoryError」が発生します。

java.lang.OutOfMemoryError: Java ヒープ スペース例外が発生した場合、Java 仮想マシンのヒープ メモリが不足していることを意味します。理由は2つあります。

a. Java 仮想マシンのヒープメモリ設定が不十分です。パラメータ -Xms と -Xmx を使用して調整できます。

b.コード内に大量の大きなオブジェクトが作成され、長時間ガベージコレクターで収集できない(参照される)状態になります。

② 退職エリア

廃止領域は、新規領域から選択された Java オブジェクトを格納するために使用されます。通常、プール オブジェクトはこの領域でアクティブになります。

③ 常設エリア

永続ストレージ領域は、JDK 自体が持つクラスとインターフェースのメタデータを格納するために使用される常駐メモリ領域です。つまり、動作環境に必要なクラス情報を格納します。この領域にロードされたデータは、ガベージ コレクターによってリサイクルされません。この領域が占有するメモリは、JVM がシャットダウンされたときにのみ解放されます。

java.lang.OutOfMemoryError: PermGen space が表示される場合、Java 仮想マシンに永続世代用の Perm メモリが不足していることを意味します。理由は2つあります。

a.プログラムの起動には、多数のサードパーティの jar パッケージを読み込む必要があります。たとえば、1 つの Tomcat にデプロイされているアプリケーションが多すぎる場合などです。

b.動的リフレクションによって生成された多数のクラスが継続的にロードされ、最終的に Perm 領域がいっぱいになります。

例:

Jdk1.6 以前: 定数プールは永続世代に割り当てられます。

JDK 1.7: はい、ただし、永続世代は徐々に削除されています。

Jdk1.8 以降: なし (java.lang.OutOfMemoryError: PermGen スペース、このエラーは JDK1.8 では発生しません)。

説明: メソッド領域とヒープメモリの不一致:

実際、メソッド領域はヒープと同様に、すべてのスレッドで共有されるメモリ領域です。仮想マシンによってロードされたクラス情報 + 共通定数 + 静的定数 + コンパイラによってコンパイルされたコードなどを格納するために使用されます。JVM 仕様ではメソッド領域はヒープ論理部分として説明されていますが、ヒープから分離することを目的とした Non-Heap というエイリアスもあります。

HotSpot 仮想マシンの場合、多くの開発者はメソッド領域を「Permanent Generation (Parmanent Gen)」と呼ぶことに慣れていますが、厳密に言えば、この 2 つは異なります。つまり、メソッド領域は Permanent Generation を使用して実装されます。 Permanent Generation はメソッド area の実装です。 jdk1.7 バージョンでは、元々 Permanent Generation に配置されていた文字列定数プールが移動されました。

定数プールはメソッド領域の一部です。クラス バージョン、フィールド、メソッド、インターフェイス、その他の説明情報に加えて、クラス ファイルには定数プールも含まれています。このコンテンツは、クラスがロードされた後にメソッド領域の実行時定数プールに保存されます。

5. ヒープメモリチューニングの概要

コードテスト:

  1. パブリッククラス JVMTest {
  2.  
  3. 公共 静的void main(String[] args){
  4.  
  5. long maxMemory = Runtime.getRuntime().maxMemory(); //Java 仮想マシンが使用しようとするメモリの最大量を返します。
  6.  
  7. 長い totalMemory = ランタイム。 getRuntime().totalMemory(); //Java 仮想マシン内のメモリの合計量を返します。
  8.  
  9. システム。出力.println( "MAX_MEMORY =" +maxMemory + "(byte)," +(maxMemory/( double )1024/1024) + "MB" );
  10.  
  11. システム。 out .println( "TOTAL_MEMORY = " +totalMemory + "(byte)" +(totalMemory/( double )1024/1024) + "MB" );
  12.  
  13. }
  14.  
  15. }

注: ヒープ メモリ操作の概要を表示するには、[実行方法] -> [実行構成] に「-XX:+PrintGCDetails」と入力します。

(1)JDK 1.7の場合:

(2)JDK 1.8の場合:

6. パラメータ設定によりガベージコレクションを自動的にトリガーする:

  1. パブリッククラス JVMTest {
  2.  
  3. 公共 静的void main(String[] args){
  4.  
  5. long maxMemory = Runtime.getRuntime().maxMemory(); //Java 仮想マシンが使用しようとするメモリの最大量を返します。
  6.  
  7. 長い totalMemory = ランタイム。 getRuntime().totalMemory(); //Java 仮想マシン内のメモリの合計量を返します。
  8.  
  9. システム。出力.println( "MAX_MEMORY =" +maxMemory + "(byte)," +(maxMemory/( double )1024/1024) + "MB" );
  10.  
  11. システム。 out .println( "TOTAL_MEMORY = " +totalMemory + "(byte)" +(totalMemory/( double )1024/1024) + "MB" );
  12.  
  13. 文字列 str = "www.baidu.com" ;
  14.  
  15. while( true ){
  16.  
  17. str += str + 新しい Random().nextInt(88888888) + 新しい Random().nextInt(99999999);
  18.  
  19. }
  20.  
  21. }
  22.  
  23. }
  24.  
  25. ガベージ コレクション メカニズムの原理を確認するには、[実行方法] -> [実行構成]「-Xmx8m –Xms8m –xx:+PrintGCDetails」という設定を入力します。

ガベージ コレクション メカニズムの原理を確認するには、[実行方法] -> [実行構成] に「-Xmx8m –Xms8m –xx:+PrintGCDetails」という設定を入力します。


<<:  2020 年に注目すべき Kubernetes の 5 つのトレンド

>>:  仮想化自動化の課題がAIの重要性を浮き彫りにする

推薦する

ウェブマスターネットワークニュース: チーターは今夜ニューヨーク証券取引所に上場予定。QQとWeChatは合併するか消滅するかも

1. チーター・モバイルが今夜ニューヨーク証券取引所に上場:最高発行価格は145億ドル、時価総額は2...

ワンストップ保護 |ホスト侵入検知UHIDS(商用版)が正式にリリースされました!

5月30日、UCloud ホスト侵入検知製品 (UHIDS) はパブリックベータ版を終了し、商用バー...

virpus-30% 割引コード/$3.5/Xen/512m メモリ/15g SSD/1.5T トラフィック/シアトル

こちらは、virpus の 30% オフの永久割引コードです。今回は、Windows を含む、vir...

httpzoom-7 USD/KVM/2 コア/512M メモリ/1T ハードディスク/6T トラフィック

httpzoom はユタ州で新製品を発表しました。これは、8 コア 16 スレッドの Xeon CP...

スパムウェブサイトクリーンアップキャンペーン

スパムリンクを識別する検索エンジンアルゴリズムがリリースされようとしています。悪があるところには、G...

SEO最適化におけるH1タグの重要性について

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っています現在、多く...

ウェブサイトへの関心を維持する10の方法

最近、Weibo を使っています。一番嬉しいのは、ファンの数が増えることです。一番嫌なのは、フォロワ...

企業がプラットフォーム・アズ・ア・サービス (PaaS) を選択すべき理由

Platform as a Service (PaaS) とは、アプリケーションの開発、実行、管理の...

Weiboマーケティングで注目すべき20の課題

ショートビデオ、セルフメディア、インフルエンサーのためのワンストップサービスWeiboマーケティング...

データセンターから端末まで、エッジAIが人工知能の新たな寵児となった理由

今日のデジタル時代において、人工知能は企業のデジタル変革の中心的な原動力となっています。ソフトウェア...

五英クラウドコンピュータは大規模な商用利用を開始し、多くの業界の顧客にサービスを提供してきました

「クラウド上で共同制作する端末です。」 5月28日、アリババクラウド社長の張建鋒氏はスピーチの中で、...

企業のウェブサイトの重量を迅速に改善するにはどうすればよいでしょうか?

企業はどのようにしてその重みを迅速に改善できるでしょうか? これは多くの SEO 初心者が懸念してい...

クラウド コンピューティングの基礎: CPU 仮想化

仮想化技術の分類には、主にサーバー仮想化、ストレージ仮想化、ネットワーク仮想化、アプリケーション仮想...

edgenat: 618 イベント、30% オフ、完全に最適化された回線、香港 VPS\韓国 VPS\米国 VPS、韓国独立サーバー

edgenat は毎年恒例の 618 イベントを開始しました。韓国の CN2 VPS、香港の CN2...

ウェブサイトの移転:計画+慎重+検査で安心して移転できます

ウェブマスターの仕事はとても大変です。私は 1 日半のハードワークの末、ウェブサイトの移転を完了しま...