数日考えた後、私は[バイトコードプログラミング]の更新を当面保留し、まず面接でよく聞かれるいくつかの知識ポイントを更新して、友人たちが面接で習得する必要のある知識とスキルを体系的に整理するのを助けることにしました。 主なアプローチは、面接でよく聞かれるさまざまな知識のポイントを、面接の観点から深く議論することです。 3 年ほど働いている Java プログラマーの場合、大企業での面接プロセスでは、面接官は、これまでにいくつのプロジェクトをこなしたか、CRUD レベルはどの程度かということにあまり注意を払わないかもしれません。特定の技術的なポイントに対する理解の深さに重点を置いています。そのため、3年くらい働いている友人は技術の深さに着目する必要があります。 今日は、JVM パフォーマンス チューニングについてお話します。この記事の主な構成は次のとおりです。 面接でよく聞かれる質問JVM に関する面接でよくある質問は、「Java で作成されたオブジェクトは JVM のどの領域に保存されますか?」です。 たとえば、ここでは次のようにコード行をリストするだけです。
上記のコードに関して、作成された User オブジェクトが JVM のヒープ領域に配置され、User オブジェクトの参照がスタックに配置されるということは多くの友人が知っています。しかし、この程度の理解しかできなければ、面接官はあなたの理解が表面的すぎると考え、面接官の要求を満たしていない可能性があります。実際、面接官はあなたが JVM についてより深く理解しているかどうかを知りたいと思っています。 この質問を面接官の視点で見ると、作成された User オブジェクトは JVM のヒープ領域に配置される、と答えるのは間違いではありません。しかし、JVM のヒープメモリ領域は若い世代と古い世代に分かれており、若い世代は Eden 領域と Survivor 領域に分かれています。 JVM ヒープ領域の論理構造を次の図に示します。 面接官がさらに知りたいのは、作成されたオブジェクトが JVM ヒープ スペースのどの特定の領域に格納されるかがわかるかどうかです。 JVM 内では、ヒープ領域全体が若い世代と古い世代に分割されます。デフォルトでは、若い世代はヒープ メモリ空間全体の 1/3 を占有し、古い世代はヒープ メモリ空間全体の 2/3 を占有します。若い世代はエデンエリアと 2 つのサバイバーエリアに分かれています。それらのデフォルトの比率は、Eden: Survivor1: Survivor2 = 8:1:1 です。 新しく作成された User オブジェクトは、JVM ヒープ スペース内の若い世代の Eden 領域に格納されますと答えることができれば、面接官は感心してあなたを見るでしょう。もちろん、ここでは JVM のエスケープ解析は考慮されていません。 JVM のエスケープ解析の詳細については、「エスケープ解析」の記事を参照してください。 JVM アーキテクチャJVM は主に、クラス ローダー サブシステム、ランタイム データ領域 (メモリ構造)、バイトコード実行エンジンの 3 つのサブシステムで構成されています。 JVM の全体的なアーキテクチャを確認するには、まず図を見てみましょう。 Java プログラムを開発する場合、まず .java ファイルを作成し、次に .java ファイルを .class ファイルにコンパイルします。 JVM では、.class ファイルの内容がクラス ローディング サブシステムを介して JVM のランタイム データ領域にロードされ、JVM のランタイム データ領域はメソッド領域、ヒープ、スタック、ローカル メソッド スタック、プログラム カウンターの複数の部分に分割されます。 クラス ファイルの内容をロードする場合、クラス ファイルの内容は複数の部分に分割され、それぞれ JVM ランタイム データ領域の複数の部分にロードされます。その中でも、プログラム カウンターの機能は、プログラムによって実行される次の命令のアドレスを記録することであることは注目に値します。 メソッド領域はメタスペースとも呼ばれ、主にランタイム定数プール、型情報、フィールド情報、メソッド情報、クラスローダー参照、対応するクラスインスタンス参照などの情報が含まれます。 JVM では、プログラムの実行は実行エンジンを通じて行われ、実行エンジンはネイティブ メソッド インターフェイスを呼び出してネイティブ メソッド ライブラリを実行し、それによってプログラム ロジック全体の実行が完了します。 よく話題になるガベージ コレクターは実行エンジンに含まれています。プログラムの実行中、実行エンジンはガベージ コレクターを起動し、バックグラウンドで実行します。ガベージ コレクターは、プログラムの実行中に生成されたメモリ ガベージ情報を継続的に監視し、対応する戦略に従ってガベージ情報をクリーンアップします。 ここで、誰もが次の点に注意する必要があります。スタック、ローカル メソッド スタック、プログラム カウンターは実行時に各スレッド専用ですが、メソッド領域とヒープはすべてのスレッドで共有されます。したがって、スタック、ローカル メソッド スタック、およびプログラム カウンターにはスレッド セーフティの問題はありませんが、メソッド領域とヒープにはスレッド セーフティの問題があります。 メソッド領域(メタスペース)多くの友人が「メソッド領域」という 3 つの単語を見ると、最初に思い浮かぶのはメソッドが格納されている場所かもしれません。 実際、メソッド領域の別名はメタスペースです。皆さんの多くは、メタスペースについてある程度聞いたことがあると思います。この領域は JDK1.8 で分割されました。主に、ランタイム定数プール、型情報、フィールド情報、メソッド情報、クラスローダー参照、対応するクラスインスタンス参照などの情報が含まれます。メソッド領域の情報は複数のスレッドで共有できます。 たとえば、プログラム内で宣言された定数、静的変数、クラス情報への参照はすべてメソッド領域に格納され、これらの参照によって指される特定のオブジェクトは通常、ヒープ内の別の領域に格納されますが、直接メモリに格納される場合もあります。 ヒープヒープには、実際に作成されたオブジェクト、つまり new キーワードによって作成されたオブジェクトが主に格納されます。ヒープ内のオブジェクトは複数のスレッドで共有できます。ヒープ内のデータは事前に明確な有効期間を持つ必要がなく、メモリを動的に割り当てることができます。使用されなくなったデータとオブジェクトは、JVM の GC メカニズムによって自動的に回収されます。 JVM パフォーマンス チューニングには通常、ヒープ メモリのチューニングが含まれます。 Java の基本型 (Byte、Short、Integer、Long、Float、Double、Boolean、Character 型データ) のラッパー クラスがヒープ内に格納されます。 ヒープは一般的に若い世代と古い世代に分けられます。若い世代はさらに 1 つのエデン エリアと 2 つのサバイバー エリアに分割されます。メモリ割り当てに関しては、デフォルト構成が維持されている場合、若い世代と古い世代のメモリサイズ比は 1:2 であり、若い世代の 1 つの Eden 領域と 2 つの Survivor 領域のメモリサイズ比は 8:1:1 です。 スタックスタックは一般的にスレッド スタックまたは仮想マシン スタックと呼ばれ、通常はローカル変数を格納します。 Java では、各スレッドには個別のスタック領域があり、各スタック内の要素はプライベートであり、他のスタックからアクセスすることはできません。スタック内のデータサイズと存続期間は固定されており、アクセス速度は比較的高速です。 Java では、すべての基本データ型 (byte、short、int、long、float、double、boolean、char) と参照変数 (オブジェクト参照) がスタック上にあります。通常、スレッドまたはメソッドが終了すると、スタック内のデータは自動的にクリアされます。 プログラムの実行中に、スタック内にメソッドごとに異なるスタック フレームが作成されます。スタック フレームには、ローカル変数テーブル、オペランド スタック、動的リンク、メソッド終了が含まれます。 ローカル変数テーブル、オペランド スタック、動的リンク、メソッド終了の具体的な機能については、Advanced Architect シリーズの今後の記事で詳しく説明します。 スタックには通常、オブジェクトへの参照が格納されます。これらの参照によって指し示される特定のオブジェクトは、通常、ヒープ内の別のアドレス空間に格納されますが、直接メモリに格納される場合もあります。 注: ここで言及されているのは、これらの参照によって指し示される特定のオブジェクトは、通常、ヒープ内の別のアドレス空間に格納されるか、または直接メモリに格納される可能性があるということです。 JVM では、エスケープ解析とスカラー置換がオンになっていると、ヒープ上にオブジェクトが作成されなくなり、オブジェクトがスタックに直接割り当てられる可能性があるためです。または、オブジェクトは作成されなくなりますが、オブジェクト内のメンバー変数がさらに分解され、スタック上に直接スペースが割り当てられ、値が割り当てられる場合があります。 ネイティブメソッドスタックローカル メソッド スタックは比較的単純で、ネイティブ メソッド エントリ領域のアドレスを保存します。 たとえば、Java でスレッドを作成し、Thread オブジェクトの start() メソッドを呼び出すと、ローカル メソッド start0() を通じてオペレーティング システムのスレッド作成メソッドが呼び出されます。この時点で、ローカル メソッド スタックは、start0() メソッドが入る領域のメモリ アドレスを保存します。 プログラムカウンタプログラム カウンター (PC カウンターとも呼ばれます) は、次に実行される命令のアドレスを格納します。 親の委任メカニズム親の委任とは何ですか? JVM では、クラスは親委任メカニズムを通じてロードされます。では、親委任メカニズムとは何でしょうか?まずは写真を見てみましょう。 JVM がクラスをロードする場合、現在のクラス ローダーを直接使用してクラスをロードすることはありません。まず、ロードするターゲット クラスを見つけるために親ローダーに委任します。ターゲット クラスが見つからない場合は、上位の親ローダーにそのクラスのロードを委任します。ブートストラップ クラス ローダーもロードするターゲット クラスを見つけられなくなるまで、独自のクラス ロード パスでターゲット クラスを検索してロードします。 簡単に言うと、親委任メカニズムは、まず親ローダーを使用してロードし、親ローダーがロードするターゲット クラスを見つけられない場合は、子ローダーを使用してそのクラス自体をロードするというものです。 親の委任を使用する理由は何ですか?ここで、次のような疑問について考えたことはありますか。なぜ JVM は親委任メカニズムを使用するのでしょうか。 問題をわかりやすく説明するために、次に示すように、java.lang パッケージを作成し、その java.lang パッケージの下に String クラスを作成します。
ここでは、java.lang.String クラスを独自に作成しますが、JDK にも java.lang.String クラスがあります。自分で作成した java.lang.String を実行すると何が起こるでしょうか?以下のエラーメッセージが出力されます。 エラー: java.lang.String クラスに main メソッドが見つかりませんでした。main メソッドを次のように定義してください:
それ以外の場合、JavaFXアプリケーションクラスはjavafx.application.Applicationを拡張する必要があります。 では、なぜ JVM は親委任メカニズムを使用するのでしょうか?私たちが自分で書いたクラスが JDK のクラスを簡単に上書きできるとしたら、JDK のコードにはまったくセキュリティがないことになるのでしょうか?そうです、JVM はコード セキュリティに親委任メカニズム、つまりサンドボックス セキュリティ メカニズムを使用します。 さらに、親委任メカニズムを使用すると、同じバイトコードの複数のコピーが JVM メモリに出現するのを防ぐこともできます。たとえば、2 つのクラス A と B の両方で System クラスをロードする必要があります。 JVM が親委任メカニズムを提供しない場合、クラス A と B はそれぞれシステム バイトコードのコピーをロードし、システム バイトコードが JVM メモリに表示されます。 逆に、JVM が親委任メカニズムを提供する場合、System クラスをロードするプロセスで、親ローダーから再帰的に検索してロードし、プロセス全体で BootStrapClassLoader ローダー (通常、ブート クラス ローダーと呼ばれる) が優先されます。見つからない場合は、サブローダーを使用して段階的にロードします。 System クラスは BootStrapClassLoader でロードできます。 System クラスがクラス A の参照を通じてロードされている場合、クラス B も System クラスをロードする必要があり、BootStrapClassLoader から System クラスのロードも開始します。このとき、BootStrapClassLoader は System クラスがロードされたことを検出し、再ロードせずにメモリ内の System に直接戻ります。 この方法では、JVM メモリ内に System クラスのバイトコードのコピーが 1 つだけ存在することになります。 クラスローダーの親子関係クラスローダーの親子関係を確認するにはどうすればいいですか?ここで、以下に示すサンプルコードを見てみましょう。
このコードも比較的単純です。 User オブジェクトを作成し、User オブジェクトのクラス ローダー、親クラス ローダー、および上位親ローダーを出力します。上記のコードを IDEA で実行すると、次の情報が出力されます。
ご覧のとおり、User オブジェクトのクラス ローダーは AppClassLoader であり、親ローダーは ExtClassLoader です。出力 null は実際には BootStrapClassLoader であり、BootStrapClassLoader は上位の親ローダーです。 このように、クラスローダーの親子関係が生まれます。AppClassLoader の親ローダーは ExtClassLoader であり、ExtClassLoader の親ローダーは BootStrapClassLoader です。 ここで、親ローダーは親クラスではないことに注意することが重要です。 クラスローダーによってロードされたクラス
注: ブートストラップ クラス ローダーと拡張クラス ローダーによってロードされるクラスは事前にロードされますが、アプリケーション クラス ローダーは、アプリケーション プロジェクトのクラスと lib の下のクラス ライブラリをロードするために使用されます。宣言されるだけで、事前に JVM メモリにロードされることはありません。使用される場合にのみ JVM メモリにロードされます。 クラスのロードプロセスJVM でのクラスの読み込みプロセスは、通常、読み込み、検証、準備、解析、初期化の順に実行されます。 ロード: 主に、コンピュータ ディスク上の IO ストリームを通じてバイトコード ファイル (.class ファイル) を読み取ります。プログラムが特定のクラスを使用する必要がある場合、たとえば、プログラム内でクラスの静的メソッドを呼び出したり、new キーワードを使用してクラスのオブジェクトを作成したりすることで、クラスがロードされます。ロード フェーズでは、このクラスを表す Class オブジェクトが JVM のヒープ メモリに生成されることがよくあります。このオブジェクトは、JVM メソッド領域に格納されているこのクラスのさまざまなデータへのアクセス エントリとして機能し、アクセス ハンドルとも呼ばれます。
注意: クラスの静的変数には、準備フェーズと初期化フェーズの両方で値が割り当てられます。違いは、準備フェーズではクラスの静的変数にデフォルト値が割り当てられ、初期化フェーズではクラスの静的変数に実際の値が割り当てられることです。 例えば、プログラム内には次の静的変数があります。
準備フェーズでは、count にデフォルト値 0 が割り当てられ、初期化フェーズでは、count に実際に値 100 が割り当てられます。 JVM チューニングパラメータJVM では、パフォーマンス チューニングは主にヒープ (新しい世代)、メソッド領域、スタックに対して実行されます。各リージョンのチューニングパラメータは次のとおりです。
より直感的な説明のために、JVM のメモリ領域と対応するチューニング パラメータを次の図のようにまとめます。 JVM 起動パラメータを設定するときは、メソッド領域 (メタスペース) のパラメータ設定に特に注意する必要があります。 メソッド領域 (メタスペース) には、-XX:MetaspaceSize と -XX:MaxMetaspaceSize という 2 つの主要な JVM パラメーターがあります。 -XX:MetaspaceSize: フル GC をトリガーするメソッド領域 (メタスペース) の初期メモリ サイズ (バイト単位) を示します (メソッド領域の初期メモリ サイズは固定されていません)。デフォルトは 21M です。設定された値に達すると、Full GC がトリガーされ、ガベージ コレクターがこの値を変更します。 Full GC が発生したときに大量のメモリ領域が再利用される場合、ガベージ コレクターはこの値のサイズを適切に縮小します。フル GC が発生したときに解放されるスペースが少ない場合、この値は、設定された -XX:MetaspaceSize 値を超えずに適切に増加されます。また、-XX:MetaspaceSize 値が設定されていない場合は 21M を超えないように増加されます。 -XX:MaxMetaspaceSize: メソッド領域 (メタスペース) の最大値を参照します。デフォルト値は -1 であり、ヒープ メモリ サイズによって制限されません。現時点では、ローカル メモリのサイズによってのみ制限されます。 最後に、メソッド領域 (メタスペース) のサイズを調整すると、非常にコストのかかる操作である Full GC が発生することに注意することが重要です。アプリケーションの起動時に Full GC が発生する場合は、メソッド領域 (メタスペース) のサイズが動的に調整されている可能性が非常に高くなります。 そのため、JVM がメソッド領域 (メタスペース) のサイズを動的に調整して Full GC が頻繁に発生するのを防ぐために、-XX:MetaspaceSize と -XX:MaxMetaspaceSize は通常同じ値に設定されます。例えば、物理メモリが8Gの場合、これら2つの値を256Mに設定できます。 最後に、8G の物理メモリでアプリケーションを起動するときに設定できる JVM パラメータを見てみましょう。もちろん、ここで示すのは経験的な値です。実際に本番環境に導入する場合は、最適なパラメータ値を見つけるためにストレス テストが必要になります。
Tomcat bin ディレクトリの catalina.sh ファイルで設定します。
Tomcat bin ディレクトリの catalina.bat ファイルで設定します。
要約するこの記事では、面接の文脈で JVM に関する一般的な質問について説明します。この記事は、大手インターネット企業の面接における JVM の重要性を説明するために、一般的な面接の質問の例から始まります。次に、メソッド領域 (メタスペース)、ヒープ、スタック、ローカル メソッド スタック、プログラム カウンターを含む JVM アーキテクチャについて説明します。 次に、JVM の親委任メカニズムが紹介され、親委任とは何か、親委任メカニズムが使用される理由、クラスローダーの親子関係について説明しました。ここで言うクラスローダーの親子関係は、親クラスと子クラスの関係ではないことに注意してください。次に、各クラスローダーがどのクラスをロードするかを紹介します。 次に、主にロード、検証、準備、解析、初期化の手順を含むクラス ロード プロセスについて説明します。同時に、各ステップの主な機能についても説明します。 最後に、JVM でよく使用されるチューニング パラメータについて紹介します。ヒープ、新しい世代、メソッド領域 (メタスペース)、スタック (スレッド) など、よく使用されるチューニング パラメータについて説明します。 Tomcat チューニングを例に、これらのチューニング パラメータの使用方法を詳しく説明します。 これらすべてをマスターしましたか? この記事はWeChatの公開アカウント「Glacier Technology」から転載したものです。下のQRコードからフォローできます。この記事を転載する場合は、Glacier Technology 公式アカウントまでご連絡ください。 |
>>: 企業が今すぐデータセンターからクラウドプラットフォームに移行すべき理由
dotblock.com は HostRocket.com (1999 年設立、仮想ホスティング、リ...
インターネットは最も急速に変化する分野の 1 つです。検索エンジンのアルゴリズムを見ればそれがわかり...
多くの人がパーティーを開かない理由は、パーティーを開くのが面倒だからです。ご存知のとおり、パーティー...
序文タオバオの最新の動きは大きなもので、6月1日からタオバオの商品検索サービスを禁止することになる。...
中国のパソコンユーザーにとって、パソコンにインストールされているソフトウェアのほとんどはおそらくフリ...
SEO 作業は長期にわたる体系的な作業です。ウェブサイトの最適化の初期段階では、ウェブサイトとその競...
多くの医療業界では、一般的に SEO ルートまたは Baidu 入札を採用しています。入札ランディン...
戦争について書面で語ることは軍事戦略においては大きなタブーである。ビジネスは戦場のようなものです。自...
原題: 失恋レビューサイト、「私の元カレは最高」と文句を言いたければ、見てみてください私の元彼はなぜ...
Racknerd は一度に 5 つのデータ センターを横断しています。今回は、HostCat がダラ...
クラウド コンピューティングが登場する前は、多くの企業がファイアウォール、WAF、侵入防止、脆弱性修...
オンライン マーケティングを行っている場合でも、オンライン ビジネスを開始している場合でも、オンライ...
最近、Baidu のいくつかのメジャーアップデートは、多数のウェブマスターに影響を与えており、特に ...
7月28日に行われたロンドン五輪男子体操予選では、中国が苦手とするあん馬と跳馬で決勝に進出した選手は...
ウェブサイトの外部リンクはウェブサイトのランキングに影響を与える鍵です。これはあまり説明しなくても誰...