JVMクラスローダーを整理しました

JVMクラスローダーを整理しました

以前面接に行ったとき、面接官から JVM のパフォーマンス チューニングについて質問されました。以前の会社のプロジェクトでは JVM パフォーマンス チューニングに関連する問題に遭遇したことがなかったため (これは会社のアーキテクトが考慮した問題だと感じていたため)、面接官にこの質問をされたときは完全に混乱し、当然ながら最終結果は失敗でした。 。そこで、ギャップを埋めるために、皆さんのお役に立てればと思い、JVM に関する知識を学びました。

[[334689]]

新しい知識を学ぶ前に、まず学習概要を作成し、その学習概要に従って段階的に学習し理解していきます。そのため、JVM の新しいテクノロジーを学習する際には、JVM クラス ローダー、JVM メモリ構造、JVM ガベージ コレクションの 3 つのセクションに分けて学習しました。今日の記事は JVM クラスローダーについてです。

1. JVMとは何か

JVM に関する理論的な知識を学習しているので、もちろん JVM が何であるかを知っておく必要があります。 JVM は Java Virtual Machine の略です。仮想マシンについて話しているところで、仮想マシンとは何なのかと疑問に思う人もいるかもしれません。ここで、仮想マシンの関連する概念を説明します。

  • 仮想マシン: 一連のコンピュータ命令を実行するために使用されるソフトウェアである仮想コンピュータです。仮想マシンは、システム仮想マシンとプログラム仮想マシンに分けられます。
  • システム仮想マシン: VMware など、物理コンピューターを完全にエミュレートし、完全なオペレーティング システムを実行できるソフトウェア プラットフォームを提供します。

プログラム仮想マシン: 単一のコンピュータ プログラムを実行するために特別に設計された Java 仮想マシンなど。 Java 仮想マシンで実行される命令は、Java バイトコード命令と呼ばれます。 (JVM はオペレーティング システム上で実行され、ハードウェアと直接やり取りすることはありません)

したがって、定義によれば、JVM はプログラム仮想マシンであることがわかります。では、JVM はどこにあるのでしょうか?実際、Java を学び始めた当初は、Java の動作環境に応じて、インターネットから JDK インストール パッケージをダウンロードする必要がありました。インストールが完了すると、インストール パスの下に Jdk と jre という 2 つのフォルダーが作成され、Java 仮想マシンは jre フォルダー内にあります。

何かが存在するなら、その存在には理由があるはずです。では、JVM の目的は何でしょうか?それは何に使われますか? JAVA を学んだ人なら誰でも、Java プログラムを実行するには、まず Java ソース プログラム (.java) をプラットフォームに依存しないバイトコード ファイル (.class) にコンパイルし、次にバイトコード ファイルをマシン コードに解釈して実行する必要があることを知っています。説明したプロセスは、Java 仮想マシンによって実行されます (理解のために下の図を参照してください)。 Java 仮想マシンはバイトコード ファイルを解釈するために使用されますが、解釈のプロセスは実際には非常に複雑なプロセスであるため、これが今日お話しするトピックです。


2. クラスの読み込み

まず、クラスロードのプロセス全体を理解しましょう。下の図から、クラスのライフサイクルは、ロード、接続(検証、準備、解析を含む)、初期化、使用(クラスのインスタンス化)、アンロード(ガベージコレクション)の 5 つの段階に分かれていることがわかります。


Java コードでは、クラス (Interface、Enum などのクラス自体を参照) の読み込み、接続、初期化のプロセスがすべてプログラム実行中に完了することは周知の事実です。次に、クラスのロード、接続、初期化について説明します。

クラスのロード: 最も一般的なケースは、既存のクラスの Class ファイル (バイトコード ファイル) をディスクからメモリにロードし、それをランタイム データ領域のメソッド領域に配置し、次にメモリ内に java.lang.Class オブジェクトを作成して、クラスのデータ構造をメソッド領域にカプセル化することです。

クラス接続(3段階に分かれています):

  • 検証: ロードされたクラスの正確性を確認する
  • 準備:クラスの静的変数(クラス変数とも呼ばれる)にメモリを割り当て、デフォルト値に初期化します(たとえば、intのデフォルト値は0です)
  • 分析: クラス内のシンボリック参照を直接参照に変換する

クラスの初期化: クラスの静的変数に値を割り当てます (コード内で上から下に実行されます)

Java プログラムでは、次の 2 つの方法でクラスを使用できます。

  • アクティブ使用
  • 受動的な使用

すべての Java 仮想マシン実装は、各クラスまたはインターフェースが Java プログラムによって「最初にアクティブに使用される」ときに、それらを初期化します。クラスは、最初にアクティブに使用されるときにのみ初期化されることに注意してください。

クラスまたはインターフェースがアクティブに使用され、初期化されている場合(この時点での初期化とは、ロードと接続(接続の3つのステップ、この時点での接続ではクラスの静的変数のメモリの割り当てが完了し、デフォルト値に初期化されるだけであることに注意してください)が完了したことを意味します)

ここでは 7 つのアクティブな用途をまとめました。

  • クラスのインスタンスを作成する
  • クラスまたはインターフェースの静的変数にアクセスするか、静的変数に値を割り当てる
  • クラスの静的メソッドを呼び出す
  • リフレクション(class.forName() など)
  • クラスのサブクラスの初期化
  • Java仮想マシンの起動時にスタートアップクラスとして指定されるクラス
  • JDK1.7 では動的言語のサポートが改善され始めました。

上記の 7 つのケースを除き、Java クラスを使用するその他の方法は、クラスの受動的な使用と見なされ、クラスの初期化にはつながりません。

3. クラスのロード、接続、初期化の詳細な説明

実際、クラスのロードの最終結果は、メモリ内に配置される Class オブジェクトであることがわかっています。 Class オブジェクトは、メソッド領域内のクラスのデータ構造をカプセル化し、メソッド領域内のデータ構造にアクセスするためのインターフェースを Java プログラマーに提供します。

上記の要約に基づいて、クラスがロードされた後にクラス接続が実際に接続ステージに入ることがわかります。接続とは、メモリに読み込まれたクラスのバイナリデータを仮想マシンの実行環境にマージすることです。では、クラス検証には何が含まれているのでしょうか?

  • クラスファイルの構造チェック
  • セマンティックチェック
  • バイトコード検証
  • バイナリ互換性の検証

4. クラスローダー

クラスのロードは実際にはクラスローダーによって行われます。クラスローダーは、JVM の動作を支援する小さな男として想像できます。では、クラスローダーの定義は何でしょうか?以下は私の個人的な理解に基づいた要約です。

クラス ローダー: クラス ローダーは、Java 仮想マシンのメモリ空間にクラスをロードするために使用されます (クラスをロードするためのツール。クラスはクラス ローダーによってロードされる必要があります)。 JDK1.2 バージョン以降では、クラスのロード プロセスで親委任メカニズムが採用されています。このメカニズムにより、Java プラットフォームのセキュリティをより確実に確保できます。この委任メカニズムでは、Java 仮想マシンに付属するルート クラス ローダー (ルート クラス ローダー自体には親ローダーがないため) を除き、残りのクラス ローダーには親ローダーが 1 つだけあります。 Java プログラムがローダー loader1 に Sample クラスのロードを要求すると、loader1 はまず親ローダーに Sample クラスのロードを委任します。親ローダーがロードできる場合、親ローダーはロードタスクを完了します。それ以外の場合は、ローダー loader1 自体が Sample クラスをロードします。

クラスローダーには 2 つの種類があります。

(1)Java仮想マシンの独自のローダー

  • ルート クラス ローダー (BootstrapClassLoader)、スタートアップ クラス ローダーとも呼ばれます。
  • 拡張クラスローダー
  • システム (アプリケーション) クラス ローダー (SystemClassLoader または AppClassLoader)

(2)ユーザー定義クラスローダー

  • java.lang.ClassLoader のサブクラス (すべてのユーザー定義クラス ローダーは抽象クラス ClassLoader を継承する必要があります)
  • ユーザーはクラスのロード方法をカスタマイズできる

クラス ローダーは、クラスをロードする前に、クラスが「初めてアクティブに使用される」まで待つ必要はありません。


5. クラスローダーの親委任メカニズムの詳細な説明

このセクションでは、クラスローダーの親委任メカニズムについて詳しく説明します。父委任機構は親委任機構とも呼ばれます (ソース コードでは parents ではなく parent となっているため、実際には父委任機構と呼ぶべきだと個人的には理解しています)。父委任機構では、各ローダーは親子関係に従っておなじみの構造を形成します (論理的には、次の図のように)。起動クラス ローダーを除き、残りのクラス ローダーには親ローダーが 1 つだけあります。

次のローダーは継承関係にあるように見えますが、実際は包含関係にあります。

父親委任メカニズムの実際の実装を示す例を挙げてみましょう。

​ 上の図の実行プロセスでクラスローダーの親委任メカニズムがどのように実行されるかを詳しく説明します。まず、loader1 と loader2 はカスタムローダーです。 Loader1 は Sample クラスをロードしようとします。父の委任メカニズムによれば、loader1 は Sample クラスを仮想マシンに直接ロードしません。代わりに、読み込みタスクをシステム クラス ローダーに転送して完了させます。次に、システム クラス ローダーはロード タスクを拡張クラス ローダーに転送し、拡張クラス ローダーはそれをルート クラス ローダーに転送して完了させます。ルート クラス ローダーはすでにクラス ローダー階層の最上位レベルであるため、ルート クラス ローダーは Sample クラスを仮想マシンにロードしようとします (ただし、ルート クラス ローダーは Sample クラスを複数の特定のディレクトリからロードされるため、ロードできません)。ルート クラス ローダーはロードを完了できないため、タスクを拡張クラス ローダーに返し (同様に、原理的にはロードできません)、その後、システム クラス ローダーにロードさせます (通常は正常にロードできます)。最後に、このプロセスは loader1 に返され、クラスのロード プロセスが完了したと宣言されます。

6. クラスローダーを取得するいくつかの方法

クラスローダーの種類がわかったので、クラスローダーを取得する方法も理解する必要があります。クラスローダーを取得する 4 つの方法をまとめました。

1 つ目は、現在のクラスの ClassLoader を取得することです。

  1. clazz.getClassLoder()

具体的な実装は以下のとおりです。

  1. クラス<? >   clazz1 =クラス.forName("java.lang.String");
  2. System.out.println(clazz1.getClassLoader());

2番目の方法: 現在のスレッドコンテキストの ClassLoader を取得します。

  1. ​ Thread.currentThread().getContextClassLoader();

具体的な実装は以下のとおりです。

  1. クラスローダーcontextClassLoader =スレッド.currentThread().getContextClassLoader();
  2. System.out.println(コンテキストクラスローダー);

3番目の方法: システム ClassLoader を取得します。

  1. ​ ClassLoader.getSystemClassLoader();

4番目: 呼び出し元のClassLoaderを取得する

  1. ​ DriverManager.getCallerLoader()

また、配列はクラスローダーによって作成されるのではなく、必要なときに JVM によって自動的に作成されることも知っておく必要があります。配列の場合、そのクラス ローダーは要素タイプのクラス ローダーと同じです。要素型がプリミティブ型の場合、配列にはクラス ローダーがありません。

ClassLoader クラス自体はデフォルトで並列処理が可能です。サブクラスが並列読み込みをサポートする場合は、サブクラス自身を登録する必要があります。ユーザー定義のローダーを並列にロードする必要がある場合は、registerAsParallelCapable() を呼び出してローダー自体を構成する必要があります。

7. 結論

上記の要約から、JVM 学習は、アプリケーション フレームワークである spring や springcloud とは異なることが実際にわかります。すぐに行動して、すぐに効果を確認することができます。 JVM はこれとは異なり、多くの理論が関係します。多くの学生は、それは重要ではなく、学ぶことに意味がないと考えるかもしれません。実際、それは武術の練習と同じです。内面の強さが十分に養われて初めて、他の動きを練習することが容易になり、上達し続けることができます。 JVM は内部の強度に相当するため、JVM を学習することは明らかに非常に重要であると考えられます。

上記は JVM クラスローダーの概要です。次の記事では、Java ソース コードと組み合わせてクラス ローダーを理解する方法について紹介します。もちろん、JVM の他のセクションの関連知識のまとめも今後紹介される予定です。

<<:  オープンソースのKVMカーネル仮想化技術とその管理方法の詳細な説明

>>:  申し訳ありませんが、インターネット上で見つかったすべての Redis 分散ロックには脆弱性があります。

推薦する

YTOエクスプレスは民間航空局に航空会社設立を申請した。

中国国際放送、北京、11月27日(記者:肖元)中国国営ラジオの「ニュース夕刊ラッシュアワー」の報道に...

Red Hat がクラウド、ネットワーク、Windows の自動化を新たにサポートする Ansible Engine 2.6 をリリース

オープンソース ソリューションのリーディング プロバイダーである Red Hat, Inc. (NY...

SEO情報は溢れています。研究のために質の高いコンテンツを選択するにはどうすればいいのでしょうか?

昨日、多くのSEO担当者の強い要望により、SEO業界最強のSEOフォーラムBSGの管理者がWeibo...

ウェブサイトを宣伝するためのWeiboの適切な使用

Weiboは今や人々の生活に欠かせないものとなり、仕事でも勉強でも、私たちはいつでもWeiboを利用...

ウェブサイトの最適化における無駄な動作を排除し、ウェブサイトの最適化効率を向上させる方法

現在、多くのウェブマスターは、ウェブサイトの最適化で目標を達成できていないと感じています。ウェブマス...

Baidu外部リンクツールの使用経験 リンク名

Baidu の外部リンク ツールはリリースされてからしばらく経っており、多くのウェブマスターが使用し...

ウェブサイトのコンテンツ収集に関する洞察

ウェブマスターなら誰でも、ウェブサイトのコンテンツこそが王であり、コンテンツこそが至高であることを知...

Netgear Orbi分散ルーティングシステム:10年前は装飾にネットワークケーブルはありませんでしたが、10年後にはその必要はありません

インターネット時代の家の装飾の一環として、インターネットケーブル + WiFi ですべてを処理できる...

企業の口コミマーケティングプロモーション戦略

オンラインプロモーションの最高レベルは、自分でプロモーションをしなくても、人気とトラフィックが上がり...

PythonでSaga分散トランザクションを簡単に完了する

[[422283]]銀行間送金業務は、典型的な分散型トランザクションのシナリオです。 A が銀行間で...

ユーザーを次のステップに導くための、ウェブサイトのホットスポットと推奨列の適切なレイアウト

A5サイズの1,000字以上の記事を閲覧するとき、左右に他のコンテンツが何もなかったら、記事を読み終...

独創性は本当に百度の「お気に入り」なのか?

独創性は、ウェブマスターの3分の2の心から消すことのできない影です。今日の大規模ウェブサイトのウェブ...

SEOの中流階級改革への道

SEO 業界は、比較的参入障壁が低く、新興業界という特性も考慮すると、現在の業界の中で最も二極化が進...