【Java】メモリ分析ツール ~ jattach ~

◾️はじめに

https://speakerdeck.com/kota2and3kan/get-heap-dump-on-jre-container?slide=35

で書かれている事とほぼ同じ内容(k8sのPod上でプロファイリングしたい)で悩んでいて
そこに記載されていた解決方法としては、「jattach」とのことなので、
調べて使ってみた。

目次

【1】jattach
【2】環境設定
 1)ダウンロード
 2)モジュールのインストール
 3)オプション:設定ファイルの配置
【3】使い方
 1)jcmdコマンドで「フライト記録を開始」するには

【1】jattach

* Javaプロファイリングするためのツール
 => C言語で記載されていて、JREだけあれば動く(JDKは不要)
 => 仕組みとしては、動的アタッチメカニズムを使用して
  JVMプロセスにコマンドを送信するユーティリティツール

https://github.com/jattach/jattach?tab=readme-ov-file#jattach

より抜粋
~~~~~~
All-in-one jmap + jstack + jcmd + jinfo
No installed JDK required, works with just JRE.
Supports Linux containers.
~~~~~~
ツール名 説明
jmap 共用オブジェクト・メモリー・マップ/ヒープ・メモリーの詳細を出力してくれるコマンドツール
jstack Java スタックトレースを出力してくれるコマンドツール
jcmd JVMに診断コマンドを送信して、実行中のJVMに対してGCの情報取得やJFRのstart/stopなどのコマンドを実行可能
jinfo 指定されたJavaプロセスに関するJava構成情報を出力してくれるコマンドツール

【2】環境設定

1)ダウンロード

https://github.com/jattach/jattach?tab=readme-ov-file#download

に従い、モジュールをダウンロードする
 => 今回の場合「jattach-linux-x64.tgz」

2)モジュールのインストール

* 解凍して、モジュール「jattach」を置くだけ

設定例: k8s のPod「flink-pod」上に設定する場合

# Step1: モジュールをローカル上に解凍
tar -xzvf jattach-linux-x64.tgz

# Step2: モジュール「jattach」を配置する
kubectl cp ./jattach <pod_name>:<path> -n <namespace>
kubectl cp ./jattach flink-pod:/opt/flink/bin/ -n flink

3)オプション:設定ファイルの配置

設定例: k8s のPod「flink-pod」上に設定する場合
https://github.com/openjdk/jdk/blob/master/src/jdk.jfr/share/conf/jfr/default.jfc

# を事前にローカル上に配置しておくこと

# kubectl cp ./default.jfc <pod_name>:<path> -n <namespace>
kubectl cp ./default.jfc flink-pod:/tmp/default.jfc -n flink

【3】使い方

基本構文

jattach <pid> [使いたいツールのコマンド]

1)jcmdコマンドで「フライト記録を開始」するには

# Step0: k8sの場合、Pod内に入る

kubectl get namespace
# => namespace: flink とする
kubectl get pod -n Flink
# => pod: flink_app とする
# kubectl exec -n <namespace> --stdin --tty <pod_name> -- <command>
kubectl exec -n flink --stdin --tty flink_app -- /bin/bash

# Step1: JavaのPIDを確認
# -A, -e(every): すべてのプロセスを表示する
ps -e
# Java 1

# Step2: jcmdコマンド実行「フライト記録を開始」
# jattach <pid> jcmd JFR.start duration=<期間> settings=<設定ファイルパス> filename=<出力ファイルパス>
attach 1 jcmd JFR.start duration=3m settings=/tmp/default.jfc filename=/tmp/outputs_$(date +"%Y%m%d_%H%M%S").jfr

# 3分間(duration=3m)後で、Podの中を出る
exit
# ローカルに出力ファイル「outputs_YYYYMMDD_HHMMDD.jfr」を持ってきて
# これを「JMC (Java Mission Control)」で開くと解析できる
kubectl cp flink flink-pod:/tmp/outputs_YYYYMMDD_HHMMDD.jfr ./outputs_YYYYMMDD_HHMMDD.jfr

補足1: jcmdコマンド
https://docs.oracle.com/javase/jp/16/docs/specs/man/jcmd.html
https://docs.oracle.com/javase/jp/7/technotes/guides/jfr/app_command_ref.html#BABGCBBA

value Explanations
JFR.start フライト記録を開始
JFR.check 実行中の記録に関する情報を表示
JFR.stop 実行中のフライト記録を停止
JFR.dump 実行中のフライト記録を停止

補足2: JMC (Java Mission Control)

* 以下の関連記事を参照の事

メモリ分析ツール ~ JFR / JMC ~
https://dk521123.hatenablog.com/entry/2014/03/17/234107

関連記事

Javaガベージコレクション
https://dk521123.hatenablog.com/entry/2018/01/01/200400
Java 〜 メモリ構造 〜
https://dk521123.hatenablog.com/entry/2014/06/14/235331
JVMのメモリ情報を出力させる
https://dk521123.hatenablog.com/entry/2014/04/08/211143
Java の Stop-The-World の調査方法
https://dk521123.hatenablog.com/entry/2025/03/10/005354
メモリ分析ツール ~ JFR / JMC ~
https://dk521123.hatenablog.com/entry/2014/03/17/234107
メモリ分析ツール ~ Memory Analyzer ~
https://dk521123.hatenablog.com/entry/2014/02/24/235516