JVMメモリリーク分析(歴史上最も完全)

記事は非常に長いので、収集してゆっくり読むことをお勧めします!備考:継続的に更新しています...

大規模な工場に参入し、構造をアップグレードし、高給を得るのに必要な古典的な本と資料:


推奨事項2:月給が50,000を超える2021年春の新入社員の面接の質問の一般的なリスト

次の面接の質問を取得します。2021年の春の新入社員の月給は50,000を超えています(強い!) Ali、Jingdong、Meituan、Toutiao ...自由に選んで横に歩いてください!
Javaの基本
1:JVMインタビューの質問(史上最強、継続的な更新、吐血の推奨) https://www.cnblogs.com/crazymakercircle/p/14365820.html
2:Javaの基本的な面接の質問(歴史上最も完全、継続的な更新、吐血の推奨) https://www.cnblogs.com/crazymakercircle/p/14366081.html
3:デッドロックインタビューの質問(史上最強、継続的に更新) [https://www.cnblogs.com/crazymakercircle/p/14323919.html]
4:デザインパターンインタビューの質問(歴史上最も包括的な、継続的な更新、吐血の推奨) https://www.cnblogs.com/crazymakercircle/p/14367101.html
5:アーキテクチャ設計のインタビューの質問(歴史上最も包括的な、継続的な更新、吐血の推奨) https://www.cnblogs.com/crazymakercircle/p/14367907.html
あります10の+面接の質問ブラッシングおよびブラッシングする必要があります 詳しくは【クレイジーメーカーサークル高並行カタログをご参照ください。

推奨事項3:Crazy Maker CirclespringCloud高並行性シリーズ

springCloud高品質のブログ投稿
nacos実際の戦闘(歴史上最も完全な) 歩哨(歴史上最も完全な+入門チュートリアル)
springcloud + webfluxの同時実行性の高い戦闘 Webflux(歴史上最も完全なもの)
SpringCloudゲートウェイ(歴史上最も完全なもの)
あり10件の+記事を磨くなり、ブラシになります高品質ボーエンの 詳しくは【クレイジーメーカーサークル高並行カタログをご参照ください。

JVMパフォーマンス最適化インタビューの質問

JVMメモリ領域の一般的な問題

Javaにメモリリークがありますか?

Javaメモリ割り当て?

Javaヒープの構造は何ですか?

ヒープ内のPermGenスペースとは何ですか?

各バージョンのメモリ領域の変更について簡単に説明してください。

各エリアの役割についてお話しください。

JVM実行サブシステムの一般的な問題

Javaクラスのロードプロセス?

クラスファイルをロードするJVMの原理とメカニズムを説明してください。クラスローダーとは何ですか。

クラスローダーとは何ですか?

クラスローダーの親委任モデルメカニズム?

ガベージコレクションに関するよくある質問

GCとは何ですか?

なぜGCがあるのですか?

Javaのガベージコレクションメカニズムについて簡単に説明してください。

オブジェクトが生きているかどうかを判断する方法は?

ガベージコレクションの利点と原則、および2種類のリサイクルメカニズムを検討しますか?

ガベージコレクターの基本原則は何ですか?

ガベージコレクターはすぐにメモリを再利用できますか?

ガベージコレクションについて仮想マシンに事前に通知する方法はありますか?

ディープコピーとシャローコピー?

System.gc()とRuntime.gc()は何をしますか?

オブジェクトの参照がnullに設定されている場合、ガベージコレクターはオブジェクトが占有しているメモリをすぐに解放しますか?

分散ガベージコレクション(DGC)とは何ですか?

それはどのように機能しますか?

シリアルコレクターとスループットコレクターの違いは何ですか?

Javaでは、オブジェクトをガベージコレクションできるのはいつですか。マイナーGCとメジャーGCについて簡単に説明してください。ガベージコレクションは、JVMの永続的な生成で発生しますか?Javaでのガベージコレクションの方法は何ですか?

パフォーマンス最適化の一般的な問題

あなたが理解している業績評価とテスト指標について教えてください。

一般的に使用されるパフォーマンス最適化方法は何ですか?

GCチューニングとは何ですか?

JVMチューニングツール

Jconsole、jProfile、VisualVM

Jconsole: jdkにはシンプルな機能が付属していますが、システムに一定の負荷がかかっている場合に使用できます。ガベージコレクションアルゴリズムの非常に詳細な追跡があります。詳細については、を参照してくださいここに

JProfiler:商用ソフトウェア、支払う必要があります。パワフル。詳細については、を参照してくださいここに

VisualVM:JDKには、JProfilerと同様の強力な機能が付属しています。お勧めします。

JVisualVMの予備調査

VisualVMはNetbeansのプロファイルサブプロジェクトであり、JDK6.0アップデート7に含まれています(Javaの起動時に特定のパラメータは必要ありません。監視ツールはbin / jvisualvm.exeにあります)。これにより、スレッド、メモリ状態、メソッドのCPU時間と、メモリ内のオブジェクト、GCされたオブジェクト、割り当てられたスタックの逆のビュー(たとえば、100個のStringオブジェクトによって割り当てられたオブジェクト)を表示します。

JDK_HOME / bin(デフォルトではC:\ Program Files \ Java \ jdk1.6.0_13 \ bin)の下に、jvisualvm.exeファイルがあります。ダブルクリックして開きます。UIから、このソフトウェアはに基づいて開発されています。 NetBeans。

リモートおよびローカルの監視を実行できます。リモート監視では、jmxを開く必要があります。これについては以下で説明します。

デフォルトのページは次のとおりです。

img

左側はローカルとリモートに分かれています。ローカルのVisualVMスレッドをダブルクリックすると、次の監視コンテンツが表示されます。

img

具体的な紹介については、以下を参照してください。

http://www.ibm.com/developerworks/cn/java/j-lo-visualvm/

VisualVMは、必要に応じてさまざまなプラグインをインストールできます。各プラグインの焦点は異なります。主にGCを監視するもの、主にメモリを監視するもの、スレッドを監視するものがあります。
ここに画像の説明を挿入
インストールする方法:

1.メインメニューから[ツール]> [プラグイン]を選択します。2. [利用可能なプラグイン]タブで、プラグインの[インストール]チェックボックスを選択します。「インストール」をクリックします。3.プラグインのインストール手順を段階的に完了します。

ここでは、Eclipse(pid 22296)を例として取り上げます。ダブルクリックして直接展開します。メインインターフェイスには、systemとjvmの2つの主要なコンテンツが表示されます。右下のjvmパラメーターとシステムプロパティをクリックして、詳細を参照してください。パラメータ情報
ここに画像の説明を挿入
。VisualVMのプラグインが多すぎるため、ここでは主に3つを紹介します。主に、監視、スレッド化、およびVisual GC
監視のいくつかを使用します。監視のホームページは、実際にはcpu、メモリ、クラスのグラフです。 、およびスレッド。
ここに画像の説明を挿入
スレッド関数とjconsole関数の間に大きな違いはありません。
ここに画像の説明を挿入
ビジュアルGCはよく使用されるものです。関数、若い世代と古い世代のメモリの変化、およびgc頻度とgc時間。
ここに画像の説明を挿入
上記の関数は、jconsoleでもほぼ使用できます。VisualVMはより包括的で直感的です。さらに、ダンプメモリスナップショットの分析、
スレッドスナップショットのダンプ、およびそれらの分析を行うことができるVisualVMの他の多くの関数があり、他にも多くのプラグインがあります。探索できるins
ここに画像の説明を挿入

実際の戦闘

メモリリークのデモをシミュレートする準備をする

1.静的変数HashMapを定義します

2.セグメントにオブジェクトを作成し、HashMapに追加します

コードは次のとおりです:

import java.util.HashMap;
import java.util.Map;
public class CyclicDependencies {
    //声明缓存对象
    private static final Map map = new HashMap();
    public static void main(String args[]){
        try {
            Thread.sleep(10000);//给打开visualvm时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //循环添加对象到缓存
        for(int i=0; i<1000000;i++){
            TestMemory t = new TestMemory();
            map.put("key"+i,t);
        }
        System.out.println("first");
        //为dump出堆提供时间
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for(int i=0; i<1000000;i++){
            TestMemory t = new TestMemory();
            map.put("key"+i,t);
        }
        System.out.println("second");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for(int i=0; i<3000000;i++){
            TestMemory t = new TestMemory();
            map.put("key"+i,t);
        }
        System.out.println("third");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for(int i=0; i<4000000;i++){
            TestMemory t = new TestMemory();
            map.put("key"+i,t);
        }
        System.out.println("forth");
        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("qqqq");
    }
}

3.次のようにjvmパラメーターを構成します。

         -Xms512m
         -Xmx512m
         -XX:-UseGCOverheadLimit
         -XX:MaxPermSize=50m

4.プログラムを実行し、visualvmモニタリングを開きます

JVisualVMはTomcatをリモートで監視します

1.リモートTomcatのcatalina.sh構成ファイルを変更し、以下を追加します。

  • JAVA_OPTS = "$ JAVA_OPTS
  • Djava.rmi.server.hostname = 192.168.122.128
  • Dcom.sun.management.jmxremote.port = 18999
  • Dcom.sun.management.jmxremote.ssl = false
  • Dcom.sun.management.jmxremote.authenticate = false "

今回は、構成は許可の検証を通過しません。jmxポートを開くだけです。

2. jvisualvmを開き、リモートを右クリックして、[リモートホストの追加]を選択します。
ここに画像の説明を挿入

3.次のように、ホストの名前を入力し、ipを直接書き込み
ここに画像の説明を挿入
ます。新しく作成したホストを右クリックし、[JMX接続の追加]を選択して、Tomcatで構成されたポートを入力します。

4.ダブルクリックして開きます。コンプリート!

JVisualVMを使用してメモリリークを分析する

1. [ビジュアルGC]タブを確認します。内容は次のとおりです。これは最初の出力のスクリーンショットです。
ここに画像の説明を挿入
これは4番目の出力のスクリーンショット
ここに画像の説明を挿入
です。2つの画像を比較すると、
ここに画像の説明を挿入
ここに画像の説明を挿入
古い世代が存在していることがわかります。 gc。プログラムを実行し続けると、旧世代のgcがまだ継続していることがわかります。
ここに画像の説明を挿入
増加7倍ですが、旧世代のメモリは減少していません。リサイクルできないオブジェクトがあることを示しています。メモリリークの可能性があります。
オブジェクトがリークしていることを分析するにはどうすればよいですか?サンプラータブを開きます。
ここに画像の説明を挿入
の図に示すようにクリックします。プログラムの出力に従ってヒープをダンプします。2番目に出力する場合は1回ダンプし、後で出力する場合は1回ダンプします。
最後のダンプからヒープラベルを入力し、カテゴリを
ここに画像の説明を挿入
クリックします。右上隅をクリックします:「別のヒープストレージと比較してください」。図に示すように、最初のエクスポートダンプコンテンツの比較を選択します。
ここに画像の説明を挿入
比較結果は次のとおりです
ここに画像の説明を挿入
。TestMemoryオブジェクトインスタンスが2回の間隔で増加していることがわかります。これは、オブジェクトにメモリリークがある可能性があります。
オブジェクト参照関係を表示する方法は?
以下に示すように、クラスTestMemoryを右クリックし、[インスタンスビューに表示]を選択します。
ここに画像の説明を挿入
左側は作成されたインスタンスの総数、右上はインスタンスの構造、以下は参照の説明です。 CyclicDependenciesクラスの図からわかります。これは、HashMapによって参照および参照されます。

このようにして、漏れの場所を特定し、実際の状況に応じて分析および解決することができます。

JVMチューニングを実行する方法

メモリの解放、コレクションクラスの検査、オブジェクトツリーを観察します

上記のチューニングツールはすべて強力な機能を提供しますが、一般的には次のカテゴリの機能に分類されます

ヒープ情報ビュー

img

ヒープスペースの割り当て(若い世代、古い世代、永続的な世代の割り当て)を表示できます

インスタントガベージコレクションを提供する

ゴミ監視(リサイクル状況を長期間監視)

img

ヒープ内のクラスとオブジェクトの情報を表示します。表示:数量、タイプなど。

img

オブジェクト参照ビュー

ヒープ情報を表示する機能により、一般的に以下の問題をスムーズに解決できます。

-老若男女のサイズ区分は妥当ですか?

- メモリーリーク

-ガベージコレクションアルゴリズムの設定が妥当かどうか

スレッドの監視

img

スレッド情報の監視:システムスレッドの数。

スレッド状態の監視:各スレッドの状態

img

ダンプスレッドの詳細:スレッドの内部操作を表示します

デッドロックチェック

ホットスポット分析

img

ホットCPU:どの方法でCPU時間がかかるかをシステムで確認してください

メモリホットスポット:システム内のどのオブジェクト(オブジェクトは特定の時間統計を生き残り、オブジェクトを一緒に破壊する)をチェックする最大数

これら2つのことは、システムの最適化に非常に役立ちます。すべてのコードを意図せずに最適化するのではなく、システムのボトルネックを検索し、見つかったホットスポットに基づいてターゲットを絞った方法でシステムを最適化できます。

スナップショット

スナップショットは、特定の瞬間まで実行されているシステムのフリーズフレームです。チューニング中は、システムのすべての変更を目で追跡することは不可能です。スナップショット関数を使用することで、システムの2つの異なるランタイムでオブジェクト(またはクラス、スレッドなど)を順番に区別できます。問題をすばやく見つけるために

たとえば、システムがガベージコレクションされた後、回復する必要のあるオブジェクトが欠落していないかどうかを確認したいと思います。次に、ガベージコレクションの前後のヒープ状況のスナップショットを作成し、2つのスナップショットのオブジェクト状況を比較できます。

メモリリークチェック

メモリリークは比較的一般的な問題であり、解決策も比較的一般的です。ここではそれに焦点を当てることができますが、スレッドとホットの問題は詳細に分析される特定の問題です。

メモリリークは、一般に、誤って使用された場合のシステムリソース(すべての側面のリソース、ヒープ、スタック、スレッドなど)として理解でき、使用済みのリソースをリサイクルできない(またはリサイクルされない)ため、新しいリソースが生成されます割り当て要求を完了できません。システムエラーが発生します。

メモリリークは、システムを直接クラッシュさせる可能性があるため、システムにとってより有害です。

最終結果は同じかもしれませんが、区別する必要があります。メモリリークとシステム過負荷には違いがあります。メモリリークは、使用済みのリソースが回復されずにエラーが発生することです。一方、システムの過負荷は、システムに割り当てるリソースがそれほど多くないことです(他のリソースが使用されています)。

旧世代のヒープスペースがいっぱいです

异常: java.lang.OutOfMemoryError:Javaヒープスペース

説明:

img

これは最も一般的なメモリリーク方法です。簡単に言えば、すべてのヒープスペースはリサイクルできないガベージオブジェクトで埋められ、仮想マシンは新しいスペースを割り当てることができなくなります。

上の図に示すように、これはメモリリークの非常に典型的なガベージコレクションの画像です。ピーク部分はすべてガベージコレクションポイントであり、ボトム部分はすべてガベージコレクション後に残っているメモリを表します。すべての谷のポイントを接続すると、下から上に線が表示されます。これは、時間の経過とともに、システムのヒープスペースが継続的に占有され、最終的にはヒープスペース全体が占有されることを示しています。したがって、システムにメモリリークがある可能性があると事前に考えることができます。(上の写真は一例に過ぎません。実際の状況では、数時間や数日など、データの収集に時間がかかります)

解決する:

この方法も比較的簡単に解決できます。一般的には、ガベージコレクション前後の状況の比較と、オブジェクト参照状況(共通収集オブジェクト参照)に基づく分析に基づいており、基本的にリークを見つけることができます。

永続的な生成が占有されています

**异常:** java.lang.OutOfMemoryError:PermGenスペース

説明:

パーマスペースが占有されています。新しいクラスにストレージスペースを割り当てることができないために発生する例外。この例外は以前は存在しませんでしたが、Javaリフレクションが頻繁に使用される今日ではより一般的です。主な理由は、動的リフレクションによって生成された多数のクラスが常にロードされているため、最終的にPerm領域がいっぱいになるためです。

さらに恐ろしいのは、異なるクラスローダーが同じクラスを使用している場合でも、すべてが同じクラスをロードすることです。これは同じことと同じです。クラスローダーがN個ある場合、N回ロードされます。したがって、この問題は基本的に解決できないと見なされる場合があります。もちろん、多数のclassLoaderと多数のリフレクションクラスが存在する場合は多くありません。

解決する:

  1. -XX:MaxPermSize = 16m

  2. JDKに切り替えます。JRocketなど。

スタックオーバーフロー

**例外:** java.lang.StackOverflowError

**注:**これについてはあまり説明しません。通常、再帰が返されないか、周期的な呼び出しが原因です。

スレッドスタックがいっぱいです

异常:致命的:スタックサイズが小さすぎます

:Javaのスレッドのスペースサイズには制限があります。JDK5.0以降、この値は1Mです。このスレッドに関連するデータが格納されます。ただし、スレッドスペースがいっぱいになると、上記の例外が発生します。

解決策:スレッドスタックサイズを増やします。-Xss2m。しかし、この構成では根本的な問題を解決することはできず、コード部分にリークがあるかどうかによって異なります。

システムメモリがいっぱいです

异常:java.lang.OutOfMemoryError:新しいネイティブスレッドを作成できません

説明

この例外は、オペレーティングシステムにこのスレッドを生成するのに十分なリソースがないことが原因で発生します。システムがスレッドを作成するとき、Javaヒープにメモリを割り当てることに加えて、オペレーティングシステム自体もスレッドを作成するためにリソースを割り当てる必要があります。したがって、スレッドの数が特定のレベルに達すると、ヒープにスペースが存在する可能性がありますが、オペレーティングシステムはリソースを割り当てることができず、この例外が発生します。

Java仮想マシンに割り当てられるメモリが多いほど、システムに残っているリソースは少なくなります。したがって、システムメモリが固定されている場合、Java仮想マシンに割り当てられるメモリが多いほど、システムが生成できるスレッドは少なくなります。関係は反比例します。 。同時に、-Xssを変更することにより、単一のスレッドに割り当てられるスペースを減らすことができます。また、システムで生成されるスレッドの総数を増やすこともできます。

解決する:

  1. システムを再設計して、スレッドの数を減らします。

  2. スレッド数を減らすことができない場合は、-Xssを使用して単一スレッドのサイズを減らします。より多くのスレッドを生成できるようにするため。

JVMパラメーター最適化の提案

基本的に、GCの数を減らします。

オブジェクトを頻繁に作成するアプリケーションであれば、若い世代のサイズを適切に増やすことができます。定数を増やすと、永続的な生成サイズが増える可能性があります。より多くのシングルトンを持つオブジェクトの場合、古い世代のサイズを増やすことができます。たとえば、春のアプリケーションで。

GCの選択、JDK5.0以降、JVMは現在のシステム構成に従って判断します通常、-Serverコマンドを実行します。gcには、シリアル、パラレル、コンカレントの3つの戦略が含まれています。

スループットは大幅に適用されます。通常、並列収集が使用され、複数のスレッドがオンになってgcが高速化されます。

応答速度の速いアプリケーションは、通常、アプリケーションサーバーなどの同時収集を使用します。

古い世代はコンカレントコレクターとして構成することをお勧めします。コンカレントコレクターはディスクを圧縮および最適化しないため、以下を構成することをお勧めします。

-XX:+ UseConcMarkSweepGC#古い世代を同時に収集する

-XX:CMSInitiatingOccupancyFraction = 80#古い世代のスペースが80%に達したときにCMSが実行されることを示します

-XX:+ UseCMSCompactAtFullCollection#古い世代の圧縮をオンにします。パフォーマンスに影響を与える可能性がありますが、メモリの断片化を排除できます。

-XX:CMSFullGCsBeforeCompaction = 10#コンカレントコレクターはメモリスペースを圧縮および整理しないため、一定期間実行すると「フラグメント」が生成され、操作効率が低下します。このパラメータは、FullGCの実行後にメモリスペースを圧縮および整理するために設定されます。

おすすめ

転載: blog.csdn.net/crazymakercircle/article/details/113758988