JVM パート 2: パフォーマンスの監視とチューニング_03_JVM の監視と診断ツール - GUI_Silicon Valley

目次

記事ディレクトリ

01-ツール概要

ターゲット Java アプリケーションのパフォーマンスに関連する基本情報は、コマンドライン ツールまたは前の章の組み合わせを使用して取得できますが、次の制限があります。

  1. メソッド間の呼び出し関係、各メソッドの呼び出し回数と呼び出し時間など、メソッド レベルの分析データを取得できません (これは、アプリケーションのパフォーマンスのボトルネックを特定するために重要です)。
  2. ユーザーは、ターゲット Java アプリケーションが配置されているホスト マシンにログインする必要があり、これはあまり便利ではありません。
  3. 分析データは端末データを通過し、結果表示は直感的ではありません。

この目的のために、JDK は jconsole、jvisualvm などのメモリ リーク分析ツールを提供して、開発者が問題を特定するのを支援しますが、これらのツールは多くの場合、迅速な特定のニーズを満たしません。そのため、ここでは比較的多くの豊富なツールを紹介します。

グラフィカルな総合診断ツール

  • JDKにはツールが付属しています
    • jconsole: JDK に付属するビジュアル監視ツール。Java アプリケーションの実行中のプロファイルを表示し、ヒープ情報、永続世代 (またはメタスペース) の使用状況、クラスのロードなどを監視します。場所: jdk\bin\jconsole.exe
    • Visual VM: Visual VM は、Java 仮想マシンで実行されている Java テクノロジ ベースのアプリケーションに関する詳細情報を表示するための視覚的なインターフェイスを提供するツールです。場所: jdk\bin\jvisualvm.exe
    • JMC: Java Mission Control、ビルトイン Java Flight Recorder。非常に低いパフォーマンス オーバーヘッドで Java 仮想マシンのパフォーマンス データを収集できます。
  • サードパーティのツール
    • MAT: MAT (Memory Analyzer Tool) は Eclipse ベースのメモリ分析ツールで、高速で機能豊富な Java ヒープ分析ツールであり、メモリ リークを見つけてメモリ消費を削減するのに役立ちます。
    • JProfiler: 有料の商用ソフトウェア。パワフル。
    • Arthas: Alibaba のオープン ソース Java 診断スペース。開発者に愛されています。
    • Btrace: Java ランタイム トレース ツール。指定したメソッド呼び出し、コンストラクター呼び出し、システム メモリなどの情報をダウンタイムなしでトレースできます。

02-JConsole

基本的な概要

  • Java5 以降、JDK に付属する Java 監視および管理コンソール。
  • これは、JVM のメモリ、スレッド、およびクラスを監視するための JMX (Java 管理拡張機能) に基づく GUI パフォーマンス監視ツールです。

公式チュートリアル: https://docs.oracle.com/javase/7/docs/technotes/guides/management/jconsole.html

起動

  • jdk/bin ディレクトリで、jconsole.exe コマンドを開始します。
  • DOS ウィンドウを開き、jconsole を直接入力します。

3つの接続方法

地元

JConsole を使用して、ローカル システムで実行されている JVM に接続します。プログラムを実行するユーザーと JConsole を実行するユーザーは、同じユーザーである必要があります。JConsole は、ファイルシステム認証を使用して、プラットフォームの MBean にリンクされた RMI 経由でサーバーに接続します。ローカル接続から監視するこの機能は、Sun の JDK でのみ使用できます。

リモート

URL service:jmx:rmi:///jndi/rmi://hostName:portNum/jmxrmi を使用して、RMI コネクタ経由で JMX エージェントに接続します。接続を確立するには、JConsole は環境変数に mx.remote.credentials を設定して、認証用のユーザー名とパスワードを指定する必要があります。

高度

特別な URL を使用して JMX エージェントに接続します。一般に、RMI によって提供されるコネクタの代わりに独自のカスタム コネクタを使用して、JMX エージェント、または JDK1.4 を使用して JMX および JMX Rmote を実装するアプリケーションに接続します。

主効果

1。概要

画像-20221003144527534

2.メモリー

画像-20221003144556699

3.糸

画像-20221003144613851

4、概要

画像-20221003144649961

03-ビジュアル VM

jvisualvm とビジュアル vm の違い

ビジュアル vm が個別にダウンロードされ、jvisualvm が JDK に付属していることを除いて、違いはありません。

基本的な概要

  • Visual VM は、トラブルシューティングとパフォーマンス監視のための強力なオールインワンの視覚化ツールです。
  • 複数の JDk コマンドライン ツールを統合し、Visual VM を使用して、仮想マシン プロセスとプロセスの構成および環境情報 (jps、jinfo) を表示し、アプリケーションの CPU、GC、ヒープ、メソッド領域、およびスレッド情報 (jstat、 jstack) など、JConsole の代わりに
  • JDK 6 Update 7 以降、Visual VM は JDK の一部としてリリースされます (VisualVM は JDK/bin ディレクトリにあります)。
  • または、Visual VM をスタンドアロン ソフトウェアとしてインストールすることもできます。

ホームページ: https://visualvm.github.io/index.html

インターフェース:

画像-20221003150100049

プラグインのインストール

Visual VM の大きな特徴は、プラグイン拡張に対応していることで、プラグインのインストールは非常に便利です。プラグイン ファイル *.nbm をオフラインでダウンロードし、ダウンロードしたプラグインを [プラグイン] ダイアログ ボックスのダウンロードしたインターフェイスに追加できます。プラグインは、利用可能なプラグイン ページからオンラインでインストールすることもできます。(インストール推奨:VisualGC)

プラグインアドレス: https://visualvm.github.io/pluginscenters.html

Visual VM に直接インストールすることもできます。[ツール] -> [プラグイン] -> [使用可能なプラグイン] -> [インストールするプラグインを選択]

接続方法

ローカル接続

ローカルJavaプロセスのCPU、クラス、スレッドなどを監視

リモート接続

1- リモート サーバーの IP アドレスを特定する

2-JMX の追加 (具体的には、JMX テクノロジを介してリモート サーバーのどの Java プロセスを監視するか)

3- bin/catalina.sh ファイルを変更して、リモートの tomcat に接続します。

4- jmxremote.access および jmxremote.password ファイルを .../conf に追加します。

5-サーバーアドレスをパブリックネットワークのIPアドレスに変更します

6-Set Alibaba Cloud セキュリティ ポリシーとファイアウォール ポリシー

7-Tomcat を起動し、Tomcat の起動ログとポート監視を表示します

8-JMXにポート番号、ユーザー名、パスワードを入力してログインする

主な機能

1. ヒープ メモリ スナップショットの生成/読み取り

画像-20221003151919007

注: プロセスが停止すると、スナップショットは失われます。保存する場合は、スナップショットを保存する必要があります。

ダンプ ファイルを保存します。

画像-20221003152042335

2. JVM パラメータとシステム プロパティを表示する

3. 実行中の仮想マシン プロセスを表示する

4. スレッド スナップショットの生成/読み取り

画像-20221003152512227

5. プログラム リソースのリアルタイム監視

6. その他の機能

  • JMX プロキシ接続
  • リモート環境モニタリング
  • CPU分析とメモリ分析

04-エクリプスマット

基本的な概要

MAT (Memory Analyzer Tool) ツールは、強力な Java ヒープ メモリ アナライザーです。メモリ リークの検出とメモリ消費の表示に使用できます。

MATはEclipseをベースに開発されており、単独で使用できるだけでなく、プラグインとしてEclipseに組み込むこともできます。非常に使いやすい無料のパフォーマンス分析ツールです。

ダウンロードアドレス:https://www.eclipse.org/mat/previousReleases.php

バージョン1.11.0をダウンロードできます

JDK がマシンにインストールされ、関連する環境変数が構成されていることを確認するだけで、MAT を正常に起動できます。

ダンプファイルを取得する

ダンプファイルの内容

MAT はヒープ ダンプ ファイルを分析できます。メモリ解析を行う場合、現在のデバイスのメモリイメージを反映したhprofファイルが得られれば、MAT展開により現在のメモリ情報を視覚的に見ることができます。

一般的に言えば、これらのメモリ情報には次のものが含まれます。

  • オブジェクト インスタンス、メンバー変数、スタックに格納されている基本型の値、ヒープに格納されている他のオブジェクトの参照値など、すべてのオブジェクト情報。
  • クラスローダー、クラス名、親クラス、静的変数などを含むすべてのクラス情報。
  • これらのオブジェクトのすべての参照パスへの GCRoot
  • スレッドのコール スタックやこのスレッドのスレッド ローカル変数 (TLS) などのスレッド情報

2点

注 1: 短所

MAT は汎用ツールではなく、すべてのタイプのヒープ ストレージ ファイルを処理できるわけではありません。ただし、Sun、HP、および SAP で使用される HPROF バイナリ ヒープ ダンプ ファイルや IBM の PHD ヒープ ストレージ ファイルなど、より主流のメーカーと形式はすべて非常にうまく解析できます。

説明 2:

最も魅力的なのは、開発者向けのメモリ リーク テーブルをすばやく生成できることです。これは、問題の特定と分析に便利です。MAT は非常に強力な機能を備えていますが、メモリの分析はワンクリックで完了するほど簡単ではなく、MAT が表示する情報から経験と勘によって発見する必要があるメモリの問題も数多くあります。

ダンプファイルを取得する

  1. jmap経由
  2. JVM パラメータを設定する
    • -XX:+HeapDumpOnOutOfMemoryError: プログラム OOM が発生すると、アプリケーションの現在のヒープ スナップショットをエクスポートします。
    • -XX:HeapDumpPath=<filename.hprof>: ヒープ スナップショットの保存場所を指定できます。
  3. ダンプ ファイルは、VisualVM を介してエクスポートできます

実稼働環境でオンラインで解析することはほとんど不可能であり、ほとんどがオフライン解析を使用しているため、jmap + MAT ツールを使用する組み合わせが最も一般的です。

ヒープ ダンプ ファイルを分析する

左上隅のファイル -> ヒープダンプを開く -> ダンプファイルを選択

画像-20221003185121365

リーク容疑者レポート

  • MAT を介して現在のメモリ リークの主な原因を自動的に分析する

コンポーネント レポート

  • 共通のルート パッケージまたはクラス ローダーに属するオブジェクトを分析するコンポーネント レポート

以前のlu実行レポートを再度開く

  • 以前の解析結果を再度開く

メインインターフェース:

[外部リンクの画像転送に失敗しました。ソース サイトにアンチリーチング メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-WkOr8xkl-1665851221026) (C:\Users\86156\AppData\Roaming\Typora\) Typora-user-images\ image-20221003191740377.png)]

ヒストグラム

MAT のヒストグラムは jmap の -histo サブコマンドと同じで、各クラスのインスタンス数とこれらのインスタンスの浅いヒープの合計を表示できます。ただし、MAT のヒストグラムは保持ヒープも計算でき、インスタンス数または保持ヒープ (デフォルトは浅いヒープ) に基づくソートをサポートします。

さらに、MAT はスーパークラス、クラス ローダー、またはパッケージ名によってヒストグラム内のクラスをグループ化することもできます。

クラスを選択すると、MAT インターフェイスの左上隅にある Instpector ウィンドウに、クラス ローダーなど、クラスの Class インスタンスに関する情報が表示されます。

各クラスのインスタンス数と、これらのインスタンスの浅いヒープまたは保持ヒープの合計を表示します

使用:

画像-20221003193126779

具体内容:

画像-20221003193207206

画像-20221003195110032

画像-20221005164602538

GC ルートを表示して、仮想/ソフト/弱参照を除外する

画像-20221005165058040

スレッドの概要

  • システム内の Java スレッドを表示する
  • ローカル変数に関する情報を表示する

見る者:

画像-20221005170505922

互いに適用されるオブジェクト間の関係を取得します

  • どのオブジェクトが参照されているかを確認するための発信参照

  • 着信参照で参照されるオブジェクト

画像-20221005180846116

浅いヒープと深いヒープ

浅いパイル

浅いヒープは、オブジェクトによって消費されるメモリを指します。32 ビット システムでは、オブジェクト参照は 4 バイト、int 型は 4 バイト、long 型変数は 8 バイト、各オブジェクト ヘッダーは 8 バイトを占有します。ヒープ スナップショットの形式によっては、オブジェクトのサイズが 8 バイトに揃えられる場合があります。

String を例にとると、2 つの int 値で合計 8 バイト、オブジェクト参照が 4 バイト、オブジェクト ヘッダーが 8 バイトの合計 20 バイトを占め、8 バイトに合わせて 24 バイトを占めます。(jdk7 で)

整数 ハッシュ32 0
整数 ハッシュ 0
参照 価値 「」

これらの 24 バイトは、String オブジェクトの浅いヒープ サイズです。String の実際の値とは関係ありません。文字列の長さに関係なく、浅いヒープ サイズは常に 24 バイトです。

オブジェクトヘッダーは、クラスに従って作成されたオブジェクトのオブジェクトヘッダーを表し、オブジェクトのサイズは8バイトに揃える必要があります

ディープ・ヒープ (保持ヒープ)

保持セット:

オブジェクト A の保持セットは、オブジェクト A がガベージ コレクションされた後に解放できるすべてのオブジェクトの組み合わせ (オブジェクト A 自体を含む) を参照します。つまり、オブジェクト A の保持セットは、オブジェクトA介して直接または間接的にのみ人為的にアクセスできます。へのすべてのオブジェクトのコレクション。簡単に言えば、オブジェクト A だけが保持するオブジェクトのコレクションを指します。

ディープヒープ (保持ヒープ):

深いヒープとは、オブジェクトの保持セット内のすべてのオブジェクトの浅いヒープ サイズの合計を指します。

注: 浅いヒープ オブジェクト自体が占有するメモリには、その内部参照オブジェクトのサイズは含まれません。オブジェクトのディープ ヒープとは、オブジェクトを介してのみ (直接または間接的に) アクセスできるすべてのオブジェクトの浅いヒープの合計、つまり、オブジェクトがリサイクルされた後に解放できる実空間を指します。

補足:オブジェクトの実寸

よく使用されるもう 1 つの概念は、オブジェクトの実際のサイズです。ここで、オブジェクトの実際のサイズは、オブジェクトが接触できるすべてのオブジェクトの浅いスタック サイズとして定義されます。これは、通常の意味でオブジェクト サイズと呼ばれるものです。ディープヒープと比べるとこちらの方が直感的で日々の開発に受け入れられているように見えますが、実はこの概念はガベージコレクションとは何の関係もありません

以下の図は、単純なオブジェクト参照図を示しており、オブジェクト A は C と D を参照し、オブジェクト B は C と E を参照しています。この場合、オブジェクト A の浅いヒープ サイズは C と D を除いた A 自体のみであり、A の時間サイズは A、C、および D の合計です。ただし、オブジェクト C はオブジェクト B からもアクセスできるため、A と A と D のディープ ヒープ サイズの合計は、オブジェクト A のディープ ヒープ範囲内にはありません。

画像-20221005183856739

練習

写真を見て保持サイズを理解してください

画像-20221005185131080

上の図では、GC ルートは A と B の 2 つのオブジェクトを直接参照しています。

A の浅いヒープ: A

A の深いヒープ: A

B の浅いヒープ: B

B のディープ ヒープ: B、C には D オブジェクトが含まれません。これは、D オブジェクトが GC ルートによって直接参照されるためです。

GC ルートが D オブジェクトを参照しない場合はどうなりますか?

画像-20221005185925784

B のディープ ヒープ: B、C、D。D は GC ルートによって直接参照されないため

ケーススタディ: StudentTrace

コード:

/**
 * -XX:+HeapDumpBeforeFullGC -XX:HeapDumpPath=d:\student.hprof
 */
public class StudentTrace {
    
    
  static List<WebPage> webPages = new ArrayList<>();

  public static void createWebPages() {
    
    
    for (int i = 0; i < 100; i++) {
    
    
      WebPage wp = new WebPage();
      wp.setUrl("http://www." + Integer.toString(i) + ".com");
      wp.setContent(Integer.toString(i));
      webPages.add(wp);
    }
  }

  public static void main(String[] args) {
    
    
    createWebPages(); // 创建了100个网页
    // 创建3个学生对象
    Student st3 = new Student(3, "Tom");
    Student st5 = new Student(5, "Jerry");
    Student st7 = new Student(7, "Lily");

    for (int i = 0; i < webPages.size(); i++) {
    
    
      if (i % st3.getId() == 0) {
    
    
        st3.visit(webPages.get(i));
      }
      if (i % st5.getId() == 0) {
    
    
        st5.visit(webPages.get(i));
      }
      if (i % st7.getId() == 0) {
    
    
        st7.visit(webPages.get(i));
      }
    }
    webPages.clear();
    System.gc();
  }

}

class Student {
    
    
  private int id;
  private String name;
  private List<WebPage> history = new ArrayList<>();

  public int getId() {
    
    
    return id;
  }

  public Student(int id, String name) {
    
    
    super();
    this.id = id;
    this.name = name;
  }

  public void visit(WebPage wp) {
    
    
    if (wp != null) {
    
    
      history.add(wp);
    }
  }
}

class WebPage{
    
    
  private String url;
  private String content;

  public String getUrl() {
    
    
    return url;
  }

  public void setUrl(String url) {
    
    
    this.url = url;
  }

  public String getContent() {
    
    
    return content;
  }

  public void setContent(String content) {
    
    
    this.content = content;
  }
}

3 つのオブジェクトの浅いヒープはすべて 24 です

画像-20221005192622708

24 の浅いヒープ サイズの分析 Source:

private int id; // 4
private String name; // 4 
private List<WebPage> history = new ArrayList<>(); // 4

int が 4 バイト、2 つの参照 4+4 が 8 バイト、オブジェクト ヘッダーが 8 バイト、合計 20 バイトが 8 にアラインされ、合計 24 バイトが占有されます。

「Lily」の履歴の elementData ディープ ヒープ サイズ 1288 のソースを分析します (私が言ったことに問題があると感じ、もう一度確認する必要があります)

画像-20221005200938437

15のウェブページ

Web ページの合計サイズ: 144 + 14 *152 = 2272 バイト -> elementData の実際のサイズです。

elementData 1288 バイトのディープ ヒープ サイズはどのように計算されますか?

7 で割り切れて 3 で割り切れる数と、7 で割り切れて 5 で割り切れる数は、0、21、42、63、84、35、70 の 7 つです。

2272 - 144 (インデックス 0 のサイズは 144) - 6 * 152 = 1216 (バイト)

1288 - 1216 を計算すると、まだ 72 バイト不足です。

この 72 バイトは何ですか?

elementData の 15 要素 * 4 バイト = 60 バイト

60 + オブジェクト ヘッダーの 8 バイト + 4 (配列自体の占有量) = 72 バイト

ドミネーターツリー

ドミネーター ツリーの概念は、グラフ理論に由来します。

MAT は、ドミネーター ツリーと呼ばれるオブジェクト グラフを提供します。支配ツリーは、オブジェクト インスタンス間の支配関係を反映します。オブジェクト参照グラフで、オブジェクト B へのすべてのパスがオブジェクト A を通過する場合、オブジェクト A はオブジェクト B を支配していると言われます。オブジェクト A がオブジェクト B に最も近いドミネーターである場合、オブジェクト A はオブジェクトBの直接のドミネーターであると見なされます。ドミネーター ツリーは、オブジェクト間の参照に基づいており、次の基本的なプロパティがあります。

  • オブジェクト A のサブツリー (オブジェクト A によって支配されるすべてのオブジェクトのコレクション) は、オブジェクト A の保持セット (保持セット)、つまりディープ ヒープを表します。
  • オブジェクト A がオブジェクト B を支配する場合、オブジェクト A の直接の支配者もオブジェクト B を支配します。
  • ドミネーター ツリーのエッジとオブジェクト参照グラフのエッジは直接オブジェクトではありません。

下の図に示すように、グラフはオブジェクト参照グラフを表し、右のグラフは左のグラフに対応するドミネーター ツリーを表します。オブジェクト A と B はルート オブジェクトによって直接支配されています. オブジェクト C へのパスは A または B を通過できるため、オブジェクト C の直接支配者もルート オブジェクトです. オブジェクト F とオブジェクト D は相互に参照します。オブジェクト F へのすべてのパスはオブジェクト D を通過する必要があるため、オブジェクト D はオブジェクト F の直接のドミネーターです。オブジェクト D へのすべてのパスは、オブジェクト C を通過する必要があります。オブジェクト F からオブジェクト D への参照がルート ノードからトリガーされた場合でも、オブジェクト C を通過します。したがって、オブジェクト D の直接ドミネーターはオブジェクト C です。

画像-20221005205​​158830

同様に、オブジェクト E はオブジェクト G を支配します。オブジェクト H に到達した人は、オブジェクト D またはオブジェクト E を通過できるため、オブジェクト D もオブジェクト E もオブジェクト H を支配することはできませんが、オブジェクト C を介して D と E の両方に到達できるため、オブジェクト C はオブジェクト H の直接支配者です。

MAT で、ツールバーのオブジェクト ドミネーター ツリー ボタンをクリックして、オブジェクト ドミネーター ツリー ビューを開きます。

画像-20221005210454458

スレッドを表示

画像-20221005210717791

クリアできる Lily サイトは 8 つだけです。つまり、Lily のオブジェクトをリサイクルした場合、これらの 8 つのサイトのみをリサイクルできます。

画像-20221005210955389

ケース: Tomcat ヒープ オーバーフロー分析

例証する

分析プロセス

補足1 再びメモリリークの話

メモリ リークの理解と分類

メモリリークとは

画像-20221005215912269

オブジェクトが使用されなくなったかどうかを判断するための到達可能性分析アルゴリズムは、基本的に、オブジェクトがまだ参照されているかどうかを判断することです。したがって、この場合、コードの実装が異なるため、さまざまな種類のメモリ リークの問題が発生します (JVM は、オブジェクトがまだ参照中であり、再利用できないと誤って認識し、メモリ リークが発生します)。

メモリリークの理解

厳密に言えば、オブジェクトがプログラムによって使用されなくなったが、GC がオブジェクトを再利用できない場合のみ、メモリ リークと呼ばれます。

しかし実際には、タイミングの悪さ(または過失)によって、オブジェクトのライフサイクルが非常に長くなり、OOM に至ることも多く、これは広義の「メモリ リーク」とも呼ばれます

画像-20221005221243063

オブジェクト X はオブジェクト Y を参照し、X のライフサイクルは Y のライフサイクルよりも長くなります。

その後、Y のライフサイクルが終了しても、X はまだ Y を参照しています。このとき、ガベージ コレクターはオブジェクト Y をリサイクルしません。

オブジェクト X がまだライフサイクルが比較的短いオブジェクト A、B、および C を参照し、オブジェクト A がオブジェクト a、b、および c も参照している場合、これにより、リサイクルできない無用なオブジェクトが大量に発生する可能性があり、メモリ リソースを占有するため、メモリが失われます。メモリがなくなるまでメモリ リークが発生します。

メモリ リークとメモリ オーバーフローの関係

(1) メモリリーク(メモリリーク)

たとえば、メモリが使い果たされて解放されない場合、合計 1024M のメモリがあり、割り当てられた 512M のメモリが再利用されていないため、使用可能なメモリは 521M のみであり、その一部がリークされたかのようになります。

(2) メモリオーバーフロー(メモリ不足)

メモリを申請するとき、十分なメモリがありません。

メモリ リークとメモリ オーバーフローの関係は次のとおりです。メモリ リークの増加は、最終的にメモリ オーバーフローにつながります。

漏れの分類

頻繁に発生: メモリ リークのあるコードが複数回実行され、実行されるたびにメモリ ブロックがリークされます。

**時折:** 特定の状況下でのみ発生します。

**1 回限り:** メモリ リークのあるメソッドは 1 回だけ実行されます。

**暗黙のリーク:** メモリを占有し続け、実行が終了するまでメモリを解放しません。厳密に言えば、これは最終的に解放されるため、メモリ リークとは見なされません。

Java でメモリ リークが発生する 8 つの状況

1. 静的コレクション クラス

HashMap、LinkedList などの静的コレクション クラス。これらのコンテナが静的である場合、そのライフ サイクルは JVM プログラムのライフ サイクルと同じであり、コンテナ内のオブジェクトはプログラムが終了する前に解放されないため、メモリ リークが発生します。簡単に言うと、有効期間の長いオブジェクトは有効期間の短いオブジェクトへの参照を保持します。

public class MemoryLeak {
    
    
	static List list = new ArrayKList();
  
  public void oomTest() {
    
    
    Object obj = new Object(); // 局部变量
    list.add(obj);
  }
}

2.シングルトンモード

シングルトン パターンは、静的コレクションがメモリ リークを引き起こす理由と似ています. シングルトンの静的な性質のために、そのライフ サイクルは JVM のライフ サイクルと同じくらい長いため、シングルトン オブジェクトが外部オブジェクトへの参照を保持している場合の場合、外部オブジェクトはリサイクルされず、メモリ リークが発生します。

3. 内部クラスは外部クラスを保持します

外部クラスのインスタンス オブジェクトのメソッドが内部クラスのインスタンス オブジェクトを返す場合、内部クラスは外部クラスを保持します。

このメモリクラスオブジェクトは、外部インスタンスオブジェクトが使用されなくなっても長い間参照されてきましたが、内部クラスが外部クラスのインスタンスオブジェクトを保持しているため、外部クラスオブジェクトはガベージコレクションされません。また、メモリ リークを引き起こします。

4. データベース接続、ネットワーク接続、IO接続などの各種接続

データベースを操作する過程で、まずデータベースへの接続を確立する必要があり、使用されなくなったら、close メソッドを呼び出してデータベースへの接続を解放する必要があります。接続が閉じられた後でのみ、ガベージ コレクターは対応するオブジェクトを回収します。

そうしないと、データベースにアクセスするプロセス中に Connection、Statement、または ResultSet が明示的に閉じられないと、多数のオブジェクトが再利用されず、メモリ リークが発生します。

5. 不合理な変数の範囲

一般に、変数の定義のスコープは、その使用のスコープよりも大きく、メモリ リークが発生する可能性があります。一方、オブジェクトが時間内に null に設定されない場合は、メモリ リークが発生する可能性があります。

6.ハッシュ値を変更する

ハッシュ値の変更. オブジェクトが HashSet コレクションに格納された後、ハッシュ値の計算に関与するオブジェクトのフィールドは変更できません。

それ以外の場合、オブジェクトが変更された後のハッシュ値は、最初に HashSet コレクションに格納されたときのハッシュ値とは異なります。この場合、オブジェクトの現在の参照を contains メソッドのパラメーターとして使用して、オブジェクトを取得します。時間内の HashSet コレクションも、オブジェクトが見つからないという結果を返します。これにより、HashSet コレクションだけから現在のオブジェクトを削除できなくなり、メモリ リークが発生します。

これが、String が不変型として設定されている理由です. String を HashSet に安全に格納するか、String を HashMap のキー値として使用できます。

7.キャッシュリーク

メモリ リークのもう 1 つの一般的な原因はキャッシュです. オブジェクト参照がキャッシュに配置されると、忘れがちです。たとえば、前のプロジェクトが初めて起動されたとき、コードがテーブルのデータをキャッシュ (メモリ) にロードするため、アプリケーションの起動が非常に遅く、テスト環境には数百のデータしかありませんでした。しかし、本番環境には数百万のデータがありました。

この問題では、WeakHashMap を使用してキャッシュを表すことができます. この種のマップの特徴は、キーがキーへの独自の参照以外に他の参照を持たない場合、マップは自動的にこの値を失うことです.

8. リスナーとコールバック

メモリ リークの 3 つ目の一般的な原因は、リスナーやその他のコールバックです。これは、クライアントが実装された API にコールバックを明示的にキャンセルせずに登録すると蓄積する可能性があります。

コールバックがすぐにガベージ コレクションされるようにする最善の方法は、弱い参照のみを保存することです (たとえば、弱い参照を WeakHashMap のキーとして保存します)。

補足1 メモリリークの事例分析

ケース

ケースコード:

public class Stack {
    
    
  private Object[] elements;

  private int size = 0;

  private static final int DEFAULT_INITIAL_CAPACITY = 16;

  public Stack() {
    
    
    elements = new Object[DEFAULT_INITIAL_CAPACITY];
  }

  public void push(Object e) {
    
    
    ensureCapacity();
    elements[size++] = e;
  }

  public Object pop() {
    
    
    if (size == 0) {
    
    
      throw new EmptyStackException();
    }
    return elements[--size];
  }

  private void ensureCapacity() {
    
    
    if (elements.length == size) {
    
    
      elements = Arrays.copyOf(elements, 2 * size + 1);
    }
  }
}

分析する

上記のプログラムには明らかなエラーはありませんが、このプログラムにはメモリ リークがあります. GC アクティビティが増加するか、メモリ使用量が増加し続けると、プログラムのパフォーマンスが低下します. 深刻な場合には、メモリ リークにつながる可能性があります.しかし、そのような失敗は比較的まれです。

コードの主な問題はpop関数です。これは、この図を通して以下に示されています

下の図に示すように、スタックが成長しているとします。

画像-20221006205539711

大量の pop 操作が実行されると、参照が空にならないため、gc は下の図に示すように参照を解放しません。

画像-20221006205621683

上の図からわかるように、スタックが最初に大きくなり、次に小さくなると、スタックからポップされたオブジェクトはガベージ コレクションされず、プログラムがスタック内のこれらのオブジェクトを使用しなくなったとしても、それらは再利用されません。これらのオブジェクトへの参照がスタック内にまだ存在するため (一般に期限切れ参照と呼ばれます)、このメモリ リークは非常に隠されています。

解決

public Object pop() {
    
    
  if (size == 0) {
    
    
    throw new EmptyStackException();
  }
  Object result = elements[--size];
  elements[size] = null;
  return result;
}

使用されなくなったら、これらの参照をクリアして、参照を空にします

画像-20221006210346361

補足 2 OQL 言語を使用したオブジェクト情報のクエリのサポート

SELECT句

MAT は SQL に似たクエリ言語 OQL (Object Query Language) をサポートしています。OQL は SQL に似た構文を使用して、ヒープ内のオブジェクトを検索およびフィルタリングします。

select * from java.util.ArrayList

返された結果セットの項目をオブジェクトとして表示するには、「OBJECTS」キーワードを使用します。

SELECT v.elementData FROM java.util.ArrayList v 

SELECT objects v.elementData FROM java.util.ArrayList v 

Select 句で、「AS RETAINED SET」キーワードを使用して、結果オブジェクトの保持セットを取得します。

SELECT AS RETAINED SET * FROM com.atguigu.mat.Student

"DISTINCT" キーワードは、結果セット内の重複オブジェクトを削除するために使用されます。

SELECT DISTINCT OBJECTS classof(s) FROM java.lang.String s

FROM 句

From 句は、クラス名、正規表現、またはオブジェクト アドレスを指定できるクエリのスコープを指定するために使用されます。

SELECT * FROM java.lang.String s

正規表現を使用して検索範囲を制限し、com.atguigu パッケージの下にあるすべてのクラスのすべてのインスタンスを出力します

SELECT * FROM "com\.atguigu\..*"

クラスのアドレスを使用して検索します。クラスのアドレスを使用する利点は、異なる ClassLoader によってロードされた同じタイプを区別できることです。

select * from 0x37a0b4d

WHERE 子句

OQLのクエリ条件を指定するにはwhere句を使います。OQL クエリは、Where 句で指定された条件を満たすオブジェクトのみを返します。Where 句の形式は、従来の SQL と非常によく似ています。

長さが 10 より大きい char 配列を返します。

SELECT *FROM Ichar[] s WHERE s.@length>10

操作パラメータが正規表現である「LIKE」演算子を使用して、「java」の部分文字列を含むすべての文字列を返します。

SELECT * FROM java.lang.String s WHERE toString(s) LIKE ".*java.*"

「=」演算子を使用して、値フィールドが null でないすべての文字列を返します。

SELECT * FROM java.lang.String s where s.value!=null

配列の長さが 15 を超え、ディープ ヒープが 1000 バイトを超えるすべての Vector オブジェクトを返します。

SELECT * FROM java.util.Vector v WHERE v.elementData.@length>15 AND v.@retainedHeapSize>1000

組み込みオブジェクトとメソッド

OQL では、ヒープ内のオブジェクトのプロパティにアクセスでき、ヒープ内のプロキシ オブジェクトのプロパティにもアクセスできます。ヒープ内のオブジェクトのプロパティにアクセスする場合、形式は次のとおりです。エイリアスはオブジェクト名です。

[ . ] . .

java.io.File オブジェクトの path プロパティにアクセスし、さらに path の value プロパティにアクセスします。

SELECT toString(f.path.value) FROM java.io.File f

String オブジェクトの内容、objectid、および objectAddress を表示します。

SELECT s.toString(),s.@objectId, s.@objectAddress FROM java.lang.String s

java.util.Vector 内部配列の長さを表示します。

SELECT v.elementData.@length FROM java.util.Vector v

すべての java.util.Vector オブジェクトとそのサブタイプを表示します

select * from INSTANCEOF java.util.Vector

すべての java.util.Vector オブジェクトとそのサブタイプを表示します

select * from INSTANCEOF java.util.Vector

JProfile

基本的な概要

Javaを実行していると、実行時のメモリ使用量をテストしたい場合があり、その際にテストツールを使用して確認する必要があります。Eclipse にはテスト可能な Eclipse メモリ アナライザー ツール (MAT) プラグインがあり、IDEA にもそのようなプラグイン (JProfiler) があります。

JProfiler は、ej-technologies が開発した Java アプリケーションのパフォーマンス診断ツールです。強力ですが、有料です。

公式ダウンロードアドレス:https://www.ej-technologies.com/download/jprofiler/files

特徴:

  • 使いやすく、フレンドリーなインターフェース操作 (シンプルで強力)
  • 分析中のアプリケーションへの影響は小さい (テンプレートを提供)
  • CPU、スレッド、メモリの解析機能が特に強力
  • jdbc、noSql、jsp、サーブレット、ソケットなどの解析をサポート。
  • 複数のモード(オフライン、オンライン)での分析をサポート
  • ローカルおよびリモート JVM の監視をサポート
  • クロスプラットフォーム、複数のオペレーティング システム インストール バージョン

主な機能

1.メソッド呼び出し

メソッド呼び出しの分析は、アプリケーションが何をしているかを理解し、そのパフォーマンスを改善する方法を見つけるのに役立ちます

2-メモリ割り当て

ヒープ、参照チェーン、およびガベージ コレクション上のオブジェクトを分析することで、メモリ リークを修正し、メモリ使用を最適化するのに役立ちます。

3-スレッドとロック

JProfiler は、マルチスレッドの問題を見つけるのに役立つ、スレッドとロックのさまざまな分析ビューを提供します

4-高度なサブシステム

多くのパフォーマンスの問題は、より高いセマンティック レベルで発生します。たとえば、JDBC 呼び出しの場合、どの SQL ステートメントの実行が最も遅いかを調べたい場合があります。JProfiler は、これらのサブシステムの統合分析をサポートします

インストールと構成(省略)

特定用途

データ収集方法

JProfier のデータ収集方法は、Sampling (サンプル収集) と Instrumentation (再構成モード) の 2 種類に分けられます。

  • Instrumentation : これは、JProfiler のフル機能モードです。クラスがロードされる前に、JProfier は関連する関数コードを分析対象のクラスのバイトコードに書き込みます。これは、実行中の jvm に一定の影響を与えます。
    • 長所:パワフル。このセットアップでは、コール スタック情報は正確です。
    • 短所: 分析するクラスが多数ある場合、アプリケーションのパフォーマンスに大きな影響を与え、CPU オーバーヘッドが高くなる可能性があります (フィルターの制御によって異なります)。したがって、このモードは通常、特定のクラスまたはパッケージのみを分析するためにフィルターと組み合わせて使用​​されます
  • サンプリング: サンプル統計と同様に、各スレッド スタック内のメソッド スタック内の情報が一定時間 (5ms) ごとにカウントされます。
    • 利点: CPU のオーバーヘッドが非常に低く、アプリケーションによる影響はほとんどありません (フィルターを構成しなくても)。
    • 短所: 一部のデータ/機能を提供できない (例: メソッドの呼び出し時間、実行時間)

注: JProfiler 自体はデータ コレクション タイプを示しません。ここでのコレクション タイプは、メソッド呼び出しのコレクション タイプです。JProfiler のコア機能のほとんどは、メソッド呼び出しによって収集されたデータに依存しているため、JProfiler のデータ収集タイプと直接見なすことができます。

リモート センシング モニタリング テレメトリ

画像-20221006234757901

メモリ ビュー ライブ メモリ

ライブ メモリ メモリ分析: クラス/クラス インスタンスに関する情報。たとえば、オブジェクトの数とサイズ、オブジェクト作成のメソッド実行スタック、オブジェクト作成のホットスポットなどです。

  • すべてのオブジェクト すべてのオブジェクト

    ロードされたすべてのクラスのリストと、ヒープに割り当てられたインスタンスの数を表示します。Java 1.5 (JVMTI) のみがこのビューを表示します。

画像-20221006235019654

  • 記録されたオブジェクト 記録されたオブジェクト

    特定の期間におけるオブジェクトの割り当てを表示し、割り当てのコール スタックを記録します。

  • アロケーション アクセス ツリー アロケーション コール ツリー

    リクエスト ツリーまたはメソッド、クラス、パッケージ、または J2EE コンポーネントを、選択したクラスの注釈付き割り当て情報とともに表示します。

  • 割り当てホット スポット

    選択したクラスに割り当てられたメソッド、クラス、パッケージ、または J2EE コンポーネントのリストを表示します。現在の値にラベルを付けて、差の値を表示できます。ホットスポットごとに、そのトレース ツリーを表示できます。

  • クラストラッカー クラストラッカー

    クラス トレース ビューには、選択したクラスとパッケージのインスタンスと時間を示すグラフをいくつでも含めることができます

分析: メモリ内のオブジェクトに何が起こるか

  • Java オブジェクトの頻繁な作成: 無限ループ、ループが多すぎる
  • 大きなオブジェクトがあります: ファイルを読み取るとき、読み取り中に byte[] を書き込む必要があります。長時間書き出さないと、byte[]が大きくなりすぎます
  • メモリリークがあります

知らせ:

  • すべてのオブジェクトの背後にあるサイズは、浅いヒープ サイズです。

ヒープ トラバーサル ヒープ ウォーカー

画像-20221008224606941

画像-20221008224904787

画像-20221008224832616

ダイアグラム参照関係の表示

画像-20221008225245798

画像-20221008225156066

メインインターフェース

画像-20221008230031206

CPU ビュー CPU ビュー

JProfier は、パフォーマンスと詳細を最適化するためにアクセス ツリーを記録するさまざまな方法を提供します。スレッドまたはスレッド グループとスレッドの状態は、すべてのビューで選択できます。すべてのビューは、メソッド、クラス、パッケージ、または J2EE コンポーネントなどのさまざまなレイヤーに集約できます。

アクセスツリー コールツリー

JVM に記録されたすべてのアクセス キューの累積トップダウン ツリーを表示します。JDBC、JMS、および JNDI サービス リクエストには、リクエスト ツリーで注釈が付けられます。要求ツリーは、URL 上のサーブレットと JSP のさまざまなニーズに応じて分割できます。

話題のスポット話題のスポット

最も時間を消費しているメソッドのリストを表示します。ホットスポットごとにバックトラック ツリーを表示できます。ホットスポットは、メソッド要求、JDBC、JMS、および JNDI サービス要求、および URL 要求に関して計算できます。

アクセスグラフ コールグラフ

選択したメソッド、クラス、パッケージ、またはJ2EEコンポーネントから始まるアクセスキューのグラフを表示します。

メソッド統計 メソッド統計

記録されたメソッドの呼び出し時間の詳細を経時的に表示します。

画像-20221009225808446

スレッド ビュー スレッド

JProfilerは、スレッドの履歴を監視することで稼働状況を判断し、スレッド閉塞の有無を監視し、スレッドが管理するメソッドをツリー表示し、スレッドを解析することができます。

スレッド履歴 スレッド履歴

スレッドのアクティビティとスレッドの状態とともに、アクティビティのタイムラインを表示します。

スレッドモニター スレッドモニター

すべてのアクティブなスレッドとそれらの現在のステータスのリストを表示します。

スレッド ダンプ スレッド ダンプ

すべてのスレッドのスタック トレースを表示する

スレッド分析は、主に次の 3 つの領域に関係しています。

  1. Web コンテナーのスレッドの最大数。例: Tomcat のスレッド容量は、同時実行の最大数よりわずかに大きくする必要があります。
  2. スレッドブロッキング
  3. スレッドのデッドロック

モニター&ロック モニター&ロック

すべてのスレッドがロックとロック情報を保持

JVM の内部スレッドを監視し、ステータスを表示します。

  • デッドロック検出グラフ 現在のロック グラフ: JVM の現在のデッドロック グラフを表示します。
  • 現在使用されている検出器 現在のモニター: 現在使用されている検出器を表示し、関連するスレッドを含めます。
  • ロック履歴グラフ ロック履歴グラフ: JVMに記録されたロック履歴を表示します。
  • 履歴監視レコード 監視履歴: 主要な待機イベントとブロック イベントの履歴レコードを表示します。
  • 使用統計のモニター 使用統計のモニター: グループ・モニター、スレッド、およびモニター・クラスの統計モニター・データを表示します。

ケース分析

ケース1

public class JProfilerTest {
    
    
    public static void main(String[] args) {
    
    
        while (true){
    
    
            ArrayList list = new ArrayList();
            for (int i = 0; i < 500; i++) {
    
    
                Data data = new Data();
                list.add(data);
            }
            try {
    
    
                TimeUnit.MILLISECONDS.sleep(500);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }
}
class Data{
    
    
    private int size = 10;
    private byte[] buffer = new byte[1024 * 1024];//1mb
    private String info = "hello,atguigu";
}

ケース 2

public class MemoryLeak {
    
    

    public static void main(String[] args) {
    
    
        while (true) {
    
    
            ArrayList beanList = new ArrayList();
            for (int i = 0; i < 500; i++) {
    
    
                Bean data = new Bean();
                data.list.add(new byte[1024 * 10]);//10kb
                beanList.add(data);
            }
            try {
    
    
                TimeUnit.MILLISECONDS.sleep(500);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }

}

class Bean {
    
    
    int size = 10;
    String info = "hello,atguigu";
    static ArrayList list = new ArrayList();
}

実行中のインスタンスをマークして、原因となったオブジェクトを特定します

画像-20221009235446577

画像-20221009235509712

画像-20221009235602753

画像-20221009235620287

理由を見つけた

画像-20221009235654267

画像を使用して表示する

画像-20221009235821130

バイト配列が最終的にBeanによって参照されていることがわかります

画像-20221009235835993

06-アーサス

基本的な概要

バックグラウンド

この 2 つのツール、Jvisualvm と Jprofile は、業界でも比較的知名度が高く、グラフィカル インターフェイスで各次元のパフォーマンス データを確認し、これらのデータに基づいて包括的な分析を行うことができるという利点があります。次に、パフォーマンスの問題が発生する場所を特定します。

しかし、これら 2 つのツールにも欠点があり、どちらもサーバー側のプロジェクト プロセス中に関連する監視パラメーターを構成する必要があります。その後、ツールはプロジェクト プロセスにリモートで接続し、関連データを取得します。これにより、オンライン環境のネットワークが分離され、ローカル監視ツールがオンライン環境にまったく接続できなくなるなど、不便が生じます。また、JProfiler などの商用ツールには支払いが必要です。

では、リモート接続を必要とせず、監視パラメーターの構成を必要とせず、豊富なパフォーマンス監視データも提供するツールはありますか?

答えはAlibaba のオープン ソース パフォーマンス分析マジック Arthas (アルザス)

概要

Artha (アルザス) は Alibaba のオープン ソース Java 診断ツールで、開発者の間で非常に人気があります。再起動せずにオンラインで問題をトラブルシューティングし、Java コードを動的に追跡し、JVM の状態をリアルタイムで監視します。

ArthasJDK 6+ をサポートし、Linux/Mac/Windows をサポートし、コマンド ライン インタラクティブ モードを採用し、豊富なTabオート問題の特定と診断をさらに容易にします。

同様の問題に遭遇し、どうすることもできないと感じた場合、Arthas は次のことをお手伝いします。

  • このクラスはどの jar パッケージからロードされますか? さまざまな種類の関連する例外が報告されるのはなぜですか?
  • 変更したコードが実行されないのはなぜですか? 私がコミットしていないということでしょうか?分岐がおかしい?
  • 問題が発生し、オンラインでデバッグできない場合、ログを追加することによってのみ再発行できますか?
  • オンラインで特定のユーザーのデータ処理に問題が発生しましたが、オンラインでもデバッグできず、オフラインでも再現できません。
  • システムの健全性をグローバルに把握できますか?
  • JVM のリアルタイムの実行状況を監視する方法はありますか?
  • アプリケーションのホットスポットをすばやく見つけてフレーム グラフを生成する方法は?
  • JVM内から直接クラスのインスタンスを見つける方法は?

画像-20221010233314993

公式アドレス:https://arthas.aliyun.com/

インストールと使用

開始コマンド

java -jar arthas-boot.jar

中国語の文書もあるため、主な学習は公式文書を参照することです。

07-Java ミッション コントロール

歴史

Oracle が Sun を買収する前、Oracle の JRockit 仮想マシンは、JRockit Mission Control と呼ばれる仮想マシン診断ツールを提供していました。

Oracle が Sun を買収した後、Oracle は Hotspot と JRockit 仮想マシンの両方を所有していました。Oracle の Java に対する戦略に従って、今後の開発では、JRokit の優れた機能が Hotspot に移植されます。重要な改善点の 1 つは、Sun の JDK に JRockit サポートが追加されたことです。

Oracle JDK 7u40 以降、ツール Mission Control は Oracle JDK にバンドルされています。

Java11以降、このセクションで紹介するJFRはオープンソース化されています。ただし、以前の Java バージョンでは、JFR は商用機能に属し、Java 仮想マシン パラメータ -XX:+UnlockCommercialFeatures によって有効化されていました。

Java が公式に提供する強力なツールである Java Mission Control (略して JMC) は、Java アプリケーションを管理、監視、プロファイリング、およびトラブルシューティングするためのツール スイートです。これには、GUI クライアントと、Java 仮想マシンのパフォーマンス データを収集するために使用される多くのプラグインが含まれています。たとえば、JMX コンソール (システムに仮想マシン データを格納するために使用される MXBean にアクセスできます) や、仮想マシンに組み込まれた効率的なプロファイリング ツール Java Flight Recorder などがあります。マシン (JFR)。

JMC のもう 1 つの利点は、従来のコード埋め込みテクノロジの代わりにサンプリングを使用することです。これは、アプリケーションのパフォーマンスにほとんど影響を与えず、ストレス テストのために JMC を実行することが完全に可能です (唯一の影響は、完全な gcs が多すぎることです)。 )。

公式アドレス: https://github.com/JDKMissionControl/jmc

起動

画像-20221013225635880

概要

Java Mission Control (略して JMC) は、Java が公式に提供する強力なツールです。これは、Java アプリケーションを管理、監視、プロファイリング、およびトラブルシューティングするためのツールです。

GUI クライアントと、JMX コンソール (仮想マシンの各サブシステムの実行データを格納するために使用される MXBean にアクセスできる) などの Java 仮想マシンのパフォーマンス データを収集するための多くのプラグインと、組み込みの効率的なプロファイリング ツール Java Filght Recorder (JFR)。

JMC のもう 1 つの利点は、従来のコード埋め込みテクノロジの代わりにサンプリングを採用していることです。これは、アプリケーションのパフォーマンスにほとんど影響を与えません。完了後、JMC をオンにしてストレス テストを行うことができます (唯一の影響は、完全な gcs が多すぎることです)。 )。

機能: JVMランタイムのステータスのリアルタイム監視

画像-20221013230511815

画像-20221013230633963

別のアイテムを追加

画像-20221013230742188

Javaフライトレコーダ

イベントタイプ

開始すると、JFR は実行中に発生する一連のイベントを記録します。これらには、Java レベルのイベントが含まれます。スレッド イベント、ロック時間、Java 仮想マシン内の時間 (新しいオブジェクトの作成、ガベージ コレクション、ジャストインタイム コンパイル時間など)。

JFR時間は、発生のタイミングと期間によって4種類あり、以下のとおりです。

  1. 瞬間的なイベント(Instant Event)、例外やスレッド開始イベントなど、ユーザーは発生するかどうかが気になります。
  2. 継続的なイベント (期間イベント)、ユーザーはガベージ コレクション イベントなどの期間を気にします。
  3. 時限イベントは、期間が指定されたしきい値を超える永続的なイベントです。
  4. サンプル イベントは定期的なサンプリング イベントです。

サンプリング イベントの一般的な例の 1 つは、メソッド サンプリング (メソッド サンプリング) です。これは、各スレッドのスタック トレースを一定間隔でカウントします。これらのサンプリングされたトレースの中に繰り返しメソッドがある場合、そのメソッドがホットスポット メソッドであると推測できます。

起動

方法 1: -XX:StartFlightRecording= パラメータを使用する

画像-20221015235902800

方法 2: jcmd の JFR.* サブコマンドを使用する

画像-20221015235929892

方法 3: JMC の JFR プラグイン

画像-20221016000049182

Java Flight Recorder のサンプリング分析

1. 一般情報

画像-20221016000454960

2.メモリー

画像-20221016000513122

3.コード

画像-20221016000317007

4.糸

画像-20221016000538235

5、入出力

画像-20221016000550787

6. システム

画像-20221016000616725

7. イベント:

画像-20221016000423661

08-その他のツール

フレーム グラフ フレーム グラフ

メカニズムのパフォーマンスを追求するシナリオでは、プログラムの実行中に CPU が何をしているかを理解するために、フレーム グラフは、プログラムのライフ サイクル全体における CPU のイベント分布を表示するための非常に直感的なツールです。

フレーム グラフは、現代のプログラマーにとってなじみのないものではないはずです. このツールは、コール スタックでの CPU 消費のボトルネックを非常に直感的に示すことができます.

Java フレーム グラフに関するオンライン説明のほとんどは、Brendan Gregg のブログ (https://brendangregg.com/flamegraphs.html) からのものです。

画像-20221016001244753

フレーム グラフは、x 軸のバーの幅で時間インデックスを単純に測定し、y 軸はスレッド スタックのレベルを表します。

Tprofiler (誰も長い間維持していません)

  • 場合:

JVM チューニング用に JDK 自体が提供するツールを使用すると、TPS を 2.5 から 20 に増やし (7 倍に増加)、システムのボトルネックを正確に特定できます。

システムのボトルネックには、アプリケーションに静的オブジェクトがあまりない、多数のビジネス スレッドがライフサイクルの長い一時オブジェクトを頻繁に作成する、コードに問題があるなどがあります。

では、大量のビジネス コードの中でこれらのパフォーマンス コードを正確に特定するにはどうすればよいでしょうか。ここでは、Ali オープン ソース ツール TProfiler を使用してこれらのパフォーマンス コードを特定し、GC の頻度が高すぎるというパフォーマンスのボトルネックをうまく解決し、最終的に最後の最適化に基づいて TPS をさらに 4 増やし、つまり 100 にしました。

  • TProfiler 構成の展開、リモート操作、およびログの読み取りはそれほど複雑ではなく、操作は非常に簡単です。しかし、GC の頻度が高すぎるというパフォーマンスのボトルネックを解決するのに役立ち、すぐに効果を発揮する可能性があります。
  • TProfiler の最も重要な機能は、指定された期間内に JVM の上位メソッドをカウントする機能です. これらの上位メソッドは、JVM パフォーマンスのボトルネックを引き起こす原因である可能性が最も高いです. これは、JRockit Mission Control を含む他のほとんどの JVM チューニング ツールでは使用できません。
  • ダウンロードアドレス:https://github.com/alibaba/TProfiler

トレース

Java ランタイム トレース ツール。これは、Java プラットフォーム用の安全な動的追跡ツールです。実行中の Java プログラムを動的に追跡するために使用できます。

BTrace は、ターゲット アプリケーションのクラスを動的に調整して、トレース コード (「バイトコード トレース」) を挿入します。

あなたのキット

Jプローブ

春の洞察

おすすめ

転載: blog.csdn.net/weixin_43811294/article/details/127342971