7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Java アプリケーションの ガベージコレクション(GC) を New Relic の APM を使ってモニタリング!

Last updated at Posted at 2025-03-06

 Java の APM を活用して JVM のガベージコレクション(Garbage Collection : GC)の実行回数と実行時間を収集し可視化する方法を紹介します。
 Java アプリケーションのパフォーマンスチューニングにおいて、ガベージコレクションは重要な役割を担います。しかし、その複雑さゆえに、GC の内部動作を理解し、効果的にモニタリングすることは難しいです。この記事では、New Relic の Java APM エージェントを用いて、GC の動作(実行時間・実行回数)を詳細にモニタリングし、パフォーマンス改善に必要な情報を収集・分析する方法を紹介します。

最新のアップデートの詳細はこちら
New Relic アップデート一覧

無料のアカウントで試してみよう!
New Relic フリープランで始めるオブザーバビリティ!

今回のポイント

この記事で紹介しているポイントは、次の2つです。

1. APM で収集できる GC 関連のメトリクスとカスタマイズ方法がわかる
 Java の APM エージェントがデフォルトで収集するメトリクスと JMX のカスタムインストゥルメンテーションを使って不足している情報を収集する方法を紹介します。

2. GC のアルゴリズム毎に収集されるメトリクスを知る
 3つの GC アルゴリズム毎に収集されるメトリクスとデータを確認するためのクエリを紹介します。

APM で収集できる GC 関連のメトリクス

 APM の機能を活用すると GC の実行時間と実行回数のメトリクスを収集することが可能です。

GC の実行時間

 Java の APM エージェントは JVM のメトリクスのうち GC の実行時間をデフォルトで収集しています。
JVM_GarbageCollection.png

GC の実行時間は、 APM の JVM のページで表示されるため、簡単に確認できます。

GC_CPUTime.png

今回のサンプルは1ホストなのでJVM1つしか出ていませんが、スケールアウト構成の場合、すべて一度に確認できます.

GC の実行回数

 New Relic の APM エージェントはカスタム JMX YAML を使って JMX から特定のメトリクスを収集できるため、GC の実行回数も収集が可能です。カスタム JMX YAML の概要と細かな設定方法については下記の記事を参考にしてください。

JConsole を使って GC の実行回数の属性を確認

 JMX から値を取得するには object_nameattributes が必要です。この2つの値を JConsole 使って GC のメトリクスを確認します。JConsole の MBeans のタブを開き、java.lang -> GarbageCollector の順に展開していきます。設定している GC のアルゴリズムによって表示される内容は変わりますが、Copy 等の配下にある属性を開くと目的の object_nameattributes の値が表示されます。

JConsole.png

カスタム JMX YAML ファイルの作成

 JConsole で確認した内容をもとにカスタム JMX YAML ファイルを作成します。GC の実行回数は CollectionCount で固定ですが、object_name は GC のアルゴリズムによって変わるため、ワイルドカード(java.lang:type=GarbageCollector,name=*)を使って GC のどのアルゴリズムでも取り込めるようにします。
 表示されている値は実行された累積の値なので monotonically_increasing を使用して増分を取り込むようにしましょう。

カスタム JMX YAML
name: JMXCustomGC
version: 1.0
enabled: true
jmx:
  - object_name: java.lang:type=GarbageCollector,name=*
    metrics:
      - attributes: CollectionCount
        type: monotonically_increasing

 このファイルを所定の場所に配置してアプリケーションを開始すれば目的の GC の実行回数が取得できるようになります。

取得したメトリクスの確認方法

 取得したデータは NRQL を作成して確認する必要があります。JMXのメトリクスはタイムスライスデータとして保存されていてカスタム JMX YAML で設定した値に合わせて名称が設定されます。今回収集している GC 実行回数のメトリクスの場合は下記のようになり、{Garbage Collector名称}の部分にワイルドカードを設定した Garbage Collector の名前が設定されます。

JMX/java.lang/GarbageCollector/{Garbage Collector名称}/CollectionCount

 例えば Serial GC を使用した場合に Garbage Collector(Copy, MarkSweepCompact)のそれぞれの実行回数をVM毎に取得するクエリは下記のようになります。

FROM Metric
SELECT 
filter(sum(newrelic.timeslice.value), where metricTimesliceName = 'JMX/java.lang/GarbageCollector/MarkSweepCompact/CollectionCount') as 'MarkSweepCompact',
filter(sum(newrelic.timeslice.value), where metricTimesliceName = 'JMX/java.lang/GarbageCollector/Copy/CollectionCount') as 'Copy' 
WHERE (entityGuid='XXXXXXXXXXX EntityGUID XXXXXXXXXXX') 
FACET `host.displayName` OR `instanceName` 
LIMIT MAX TIMESERIES

image.png

 Data Explorer を使って確認することも可能です。Timeslices を選択して確認したいエンティティを設定した状態で JMX というキーワードで検索すると目的のメトリクスが表示されます。
DataExplorer.png

Data Explorer の使い方についてはこちらの記事を参考にしてください。

GC のアルゴリズム毎に収集されるメトリクス

 下記3種類のGCアルゴリズム毎にどのようなメトリクスが取得できるのかを紹介します。

  • Serial GC
  • Pararel GC
  • Garbage First GC(G1GC)

 収集された GC の実行回数と実行時間のデータは、タイムスライスメトリクスという形式でNew Relic に保管されています。タイムスライスメトリクスを NRQL や Data Explorer で参照する際には、metricTimesliceName がキーになっています。

ここでは各 GC アルゴリズムが使用している Garbage Collector 毎にどの metricTimesliceName を使用すれば良いのか、どんなクエリ(NRQL) で取得できるのかをメインに紹介します。

Serial GC

 単一スレッドで動作しオーバーヘッドが低い Serial GC は、小規模でシングルスレッド向けのアプリケーションやリソースが限られた環境に適しています。

metricTimesliceName(Serial GC)

Garbage Collector 実行回数 実行時間
Copy JMX/java.lang/GarbageCollector/Copy/CollectionCount GC/Copy
MarkSweepCompact JMX/java.lang/GarbageCollector/MarkSweepCompact/CollectionCount GC/MarkSweepCompact

実行回数(Serial GC)

ホスト毎にGCの実行回数の合計値を時系列で表示する際の例です。

  • Copy
SELECT sum(newrelic.timeslice.value) AS `Copy Count`
FROM Metric
WHERE metricTimesliceName = 'JMX/java.lang/GarbageCollector/Copy/CollectionCount' 
AND `entity.guid` = '{EntityGUID}'
FACET `host.displayName` OR `instanceName`
TIMESERIES

Copy_実行回数.png

  • MarkSweepCompact
SELECT sum(newrelic.timeslice.value) AS `MarkSweepCompact Count`
FROM Metric
WHERE metricTimesliceName = 'JMX/java.lang/GarbageCollector/MarkSweepCompact/CollectionCount' 
AND `entity.guid` = '{EntityGUID}'
FACET `host.displayName` OR `instanceName`
TIMESERIES

MarkSweepCompact_実行回数.png

実行時間(Serial GC)

ホスト毎にGCの実行時間の平均値を時系列で表示する際の例です。

  • Copy
SELECT average(newrelic.timeslice.value) AS `Copy CPU Time`
FROM Metric
WHERE metricTimesliceName = 'GC/Copy' 
AND `entity.guid` = '{EntityGUID}'
FACET `host.displayName` OR `instanceName`
TIMESERIES

Copy_実行時間.png

  • MarkSweepCompact
SELECT average(newrelic.timeslice.value) AS `MarkSweepCompact CPU Time`
FROM Metric
WHERE metricTimesliceName = 'GC/MarkSweepCompact' 
AND `entity.guid` = '{EntityGUID}'
FACET `host.displayName` OR `instanceName`
TIMESERIES

MarkSweepCompact_実行時間.png

Parallel GC

 並列にガベージコレクションを行いスループットを重視する Parallel GC は、マルチプロセッサ環境やスループットを最重視するバックエンドシステムに適しています。

metricTimesliceName(Parallel GC)

Garbage Collector 実行回数 実行時間
PS Scavenge JMX/java.lang/GarbageCollector/PS Scavenge/CollectionCount GC/PS Scavenge
PS MarkSweep JMX/java.lang/GarbageCollector/PS MarkSweep/CollectionCount GC/PS MarkSweep

実行回数(Parallel GC)

ホスト毎にGCの実行回数の合計値を時系列で表示する際の例です。

  • PS Scavenge
SELECT sum(newrelic.timeslice.value) AS `PS Scavenge Count`
FROM Metric
WHERE metricTimesliceName = 'JMX/java.lang/GarbageCollector/PS Scavenge/CollectionCount' 
AND `entity.guid` = '{EntityGUID}'
FACET `host.displayName` OR `instanceName`
TIMESERIES

PS Scavenge_実行回数.png

  • PS MarkSweep
SELECT sum(newrelic.timeslice.value) AS `PS MarkSweep Count`
FROM Metric
WHERE metricTimesliceName = 'JMX/java.lang/GarbageCollector/PS MarkSweep/CollectionCount' 
AND `entity.guid` = '{EntityGUID}'
FACET `host.displayName` OR `instanceName`
TIMESERIES

PS MarkSweep_実行回数.png

実行時間(Parallel GC)

ホスト毎にGCの実行時間の平均値を時系列で表示する際の例です。

  • PS Scavenge
SELECT average(newrelic.timeslice.value) AS `PS Scavenge CPU Time`
FROM Metric
WHERE metricTimesliceName = 'GC/PS Scavenge' 
AND `entity.guid` = '{EntityGUID}'
FACET `host.displayName` OR `instanceName`
TIMESERIES

PS Scavenge_実行時間.png

  • PS MarkSweep
SELECT average(newrelic.timeslice.value) AS `PS MarkSweep CPU Time`
FROM Metric
WHERE metricTimesliceName = 'GC/PS MarkSweep' 
AND `entity.guid` = '{EntityGUID}'
FACET `host.displayName` OR `instanceName`
TIMESERIES

PS MarkSweep_実行時間.png

Garbage First GC (G1GC)

 リージョンベースでメモリを管理し予測可能なポーズ時間を提供するG1GCは、大規模なヒープを持つアプリケーションやリアルタイムシステムに最適です。

metricTimesliceName(G1GC)

Garbage Collector 実行回数 実行時間
G1 Young Generation JMX/java.lang/GarbageCollector/G1 Young Generation/CollectionCount GC/G1 Young Generation
G1 Concurrent GC JMX/java.lang/GarbageCollector/G1 Concurrent GC/CollectionCount GC/G1 Concurrent GC
G1 Old Generation JMX/java.lang/GarbageCollector/G1 Old Generation/CollectionCount GC/G1 Old Generation

実行回数(G1GC)

ホスト毎にGCの実行回数の合計値を時系列で表示する際の例です。

  • G1 Young Generation
SELECT sum(newrelic.timeslice.value) AS `G1 Young Generation Count`
FROM Metric
WHERE metricTimesliceName = 'JMX/java.lang/GarbageCollector/G1 Young Generation/CollectionCount' 
AND `entity.guid` = '{EntityGUID}'
FACET `host.displayName` OR `instanceName`
TIMESERIES

G1 Young Generation_実行回数.png

  • G1 Concurrent GC
SELECT sum(newrelic.timeslice.value) AS `G1 Concurrent GC Count`
FROM Metric
WHERE metricTimesliceName = 'JMX/java.lang/GarbageCollector/G1 Concurrent GC/CollectionCount' 
AND `entity.guid` = '{EntityGUID}'
FACET `host.displayName` OR `instanceName`
TIMESERIES

G1 Concurrent GC_実行回数.png

  • G1 Old Generation
SELECT sum(newrelic.timeslice.value) AS `G1 Old Generation Count`
FROM Metric
WHERE metricTimesliceName = 'JMX/java.lang/GarbageCollector/G1 Old Generation/CollectionCount' 
AND `entity.guid` = '{EntityGUID}'
FACET `host.displayName` OR `instanceName`
TIMESERIES

G1 Old Generation_実行回数.png

実行時間(G1GC)

ホスト毎にGCの実行時間の平均値を時系列で表示する際の例です。

  • G1 Young Generation
SELECT average(newrelic.timeslice.value) AS `G1 Young Generation CPU Time`
FROM Metric
WHERE metricTimesliceName = 'GC/G1 Young Generation' 
AND `entity.guid` = '{EntityGUID}'
FACET `host.displayName` OR `instanceName`
TIMESERIES

G1 Young Generation_実行時間.png

  • G1 Concurrent GC
SELECT average(newrelic.timeslice.value) AS `G1 Concurrent GC CPU Time`
FROM Metric
WHERE metricTimesliceName = 'GC/G1 Concurrent GC' 
AND `entity.guid` = '{EntityGUID}'
FACET `host.displayName` OR `instanceName`
TIMESERIES

G1 Concurrent GC_実行時間.png

  • G1 Old Generation
SELECT average(newrelic.timeslice.value) AS `G1 Old Generation CPU Time`
FROM Metric
WHERE metricTimesliceName = 'GC/G1 Old Generation' 
AND `entity.guid` = '{EntityGUID}'
FACET `host.displayName` OR `instanceName`
TIMESERIES

G1 Old Generation_実行時間.png

Minor GC と Major GC

 今回紹介した 3 つの GC アルゴリズムは世代型メモリ管理を行なっています。紹介したメトリクスは下記の表のように young 領域を対象にした Minor GC と old 領域を対象とした Major GC に分けることができます。

        Minor GC Major GC
Serial GC Copy MarkSweepCompact
Palaller GC PS Scavenge PS MarkSweep
G1GC G1 Young Generation GC/G1 Old Generation, G1 Concurrent GC

 young/old領域の全てを対象にした Full GC の発生状況を把握することは Java アプリケーションを運用する上で大変重要です。Major GC のメトリクスをモニタリングすることで Full GC の発生状況を確認することが可能になります。

まとめ

 Java アプリケーションのパフォーマンスチューニングにおいて、ガベージコレクションは重要です。New Relic の APM を使って GC のメトリクスを収集・確認する方法を紹介しました。New Relic では GC だけではなく、メモリやクラス等の情報も収集しています。GC のメトリクスと関連するデータをもとにしてヒープサイズの調整やパラメータのチューニングを行い、サービスの利用状況の変化に合わせてパフォーマンスを最適化することが可能です。New Relicのテレメトリデータを使ってサービスの改善に取り組んでみてください。

 New Relicでは、新しい機能やその活用方法について、QiitaやXで発信しています!
無料でアカウント作成も可能なのでぜひお試しください!

New Relic株式会社のX(旧Twitter)Qiita OrganizationOrganizationでは、
新機能を含む活用方法を公開していますので、ぜひフォローをお願いします。

無料のアカウントで試してみよう!
New Relic フリープランで始めるオブザーバビリティ!

7
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?