unnamed

Javaとか、http://twitter.com/sugarlife

CMS GC おさらい

この記事は Java Advent Calendar 2014 の一日目の記事です。

先日の JJUG CCC 2014 FallCMS GC について話してきました。
結構遅めの時間帯にも関わらず、200人規模の部屋がいっぱいに埋まるぐらいの盛況振りで、みなさんGCにお困りなんだなあと実感しました。スライドは以下に公開しています。CMS GC の挙動から GC ログの読み方、どういうケースが厄介なのかを紹介しているので是非ご覧ください!

嬉しいことにセッションの反応は良かったのですが、「遅めの時間帯で頭も疲れてるとガチ話辛い」という声もあったので、今回は CMS GC について比較的重要な点についてだけ簡単におさらいしたいと思います。

オプションについて

@nekop さんの「Java 7 CMS GCの基本的な情報の整理 - nekop's blog」を読めば OK 。

上の記事から追記するとしたら

  • -Xmx と -Xms は同じ値にしたほうが、拡張/シュリンク時に Major GC などの負荷が発生しないのでお勧め。
    • 積極的にシュリンクさせたいなら MaxHeapFreeRatio も変更しないと多くの場合では期待している動作にならないので注意。
    • ちなみに JDK8 以前はこのバグで実はシュリンクできていなかったケースとかもある。
  • -XX:+CMSClassUnloadingEnabled は JDK8 でデフォルト True なので、もう True で良いと思う。
    • JDK 8 で False にしてると、(Metaspaceを使いまくるアプリなら) Metaspace が際限なく増えて最終的に JVM 落ちるんじゃないかな。
    • 有効にすることで増える Remark フェーズの GC ポーズの秒数は下のスライドのログ見れば解る。

他、CMS GC の発生条件のチューニングとして、以下のスライドで CMSInitiatingOccupancyFraction と UseCMSInitiatingOccupancyOnly を紹介しました。

UseCMSInitatingOccupancyOnly を使わずに、チューニングすることも可能ですが、自分が知っている限りでこれが無効の場合の CMS GC 開始条件は、

  • CMS 実行間隔の統計的に、今実行しないとヒープが不足すると判断された場合
  • 最初の CMS 実行時に、ヒープ使用率が CMSBootstrapOccupancy で指定した値を超えていた場合
  • ヒープ領域拡張した結果、GC を行わなくてもメモリ確保に成功した場合
  • 断片化によってまとまったメモリ空間の確保に失敗すると判断された場合

と、これ以外(インクリメンタル CMS やパーマネント領域関係とか)にもあるのでここら辺を一つ一つやるよりは UseCMSInitiatingOccupancyOnly で調整したほうが楽です。

GC ログの読み方について

GC ログの読み方はスライドの P.37 以降に一つ一つ書いているのでそちらで!
特に重要そうな点は以下の通りです。

  • CMS GC と Full GC は別物
    • CMS GC は Initial mark ([1 CMS-initial-mark) と Remark ([1 CMS-remark) フェーズでアプリケーションが止まる。それ以外の時間はアプリは動く。
    • Full GC は Mark Sweep Compaction アルゴリズムであり、実行時はアプリケーションが止まる。
      • promotion failed か concurrent mode failure が出力された時にFullGCが実行される。[Full GC が出力されない場合もある。
      • Full GC対策はスライド参照(P.71から)。
  • CMS: abort preclean due to time」はエラーじゃない。
  • GC locker: Trying a full collection because scavenge failed」が出たら CMS GC は諦めて コンパクションのある GC を使うのがお勧め。

おわりに

CMS GC ではパフォーマンス的にどうにもならない時もあります。どうにもならないことが掴めたら G1GC や Parallel GC、Azul Zingを使うことを検討しましょう。

これ以外にも OpenJDK にはまた新しい GC として G1GC リプレース型の Pauseless GC である Shenandoah がやってきます。JavaOne2014 でも発表していましたが、資料はこっちの方(「Shenandoah An ultra-low pause time Garbage Collector for OpenJDK」)が解りやすいかな。Remembered set絡みの処理が早くなるアイデアで、G1GC より停止時間が優れてる感じっぽいと受け取りましたが、出てくるのはしばらく後ですね。こんな感じで GC との付き合いはしばらく続きそうです。

Java 起動(Launcher)の仕組み

※:この記事は下書き中に本文ががっつり消えたため、知らずに部分的に端折ってるところがあるかもしれません。(´;ω;`)

Java、すなわち JVM (HotSpot) を立ち上げた時、どういった処理が行われているのでしょうか。正確に知りたい場合は OpenJDK のソースコードを読むのが最も確実ですが、概要レベルでどのような処理が行われていて、それがソースコードのどのあたりに書かれているのか案内があった方がすんなりと理解できます。と言うわけで、自分用のメモ書きをちょっとだけ整理してここで公開してみます。

なお、自分の理解をベースに記述しているので間違いが含まれている可能性があります。見つけた場合はそっとコメントか @sugarlife にお教え頂けると大変喜びます。

Java の動作概要について

Java、特に HotSpot の動作概要については、OpenJDK コミュニティによって「HotSpot Runtime Overview」という記事で解説されています。Java の起動時の処理についても「VM Lifecycle」という項目で説明されています。動作の概要を知りたい場合はこれらの記事を読むだけで理解できます。

和訳については有志らが取り組んでいる状況です。Java の動作に興味がある人は是非和訳をしてみませんか:)

この活動を見て、自分もこのメモ書きをちょっと手直しして公開してみようと思った次第です。

Java の起動 (Launcher)

HotSpot Runtime Overview で書かれている起動時における処理内容としては Launcher と JNI_CreateJavaVM が書かれています。Launcher というのは、ユーザが利用する java コマンド等のコマンド群 (java, javac, etc... ) 、およびそこから呼ばれるライブラリ (JLI、libjli) 部分を指します。「Launcher」とだけ書かれていた場合は、java コマンド等のコマンド群を指すことが多いです。
JNI_CreateJavaVM は The invocation API と呼ばれる API の一つで、JVM(HotSpot) そのものをロード & 初期化するメソッドです。現在の実装では一つのプロセスに複数VM は作成不可能なため、一度のみ実行されます。

ここでは主に Launcher 部分について触れて行きます。なお、ソースコードへのリンクは jdk8 の tip(最新コミット) にリンクしています。jdk8 の最新版ではないことに注意してください。最新版は jdk8 の部分を jdk8u に変えることで確認できます。

  • java コマンドを叩く
  • main() / WinMain() [jdk/src/share/bin/main.c]
  • JLI_Launch() [jdk/src/share/bin/java.c]
    • LoadJavaVM() より libjvm をロード。Linux の場合は libjvm.so ファイルをダイナミックロード。
    • HotSpot Runtime Overview に記載されている Launcher の 1. ~ 4. 部分が実行される。
    1. コマンドライン引数の解析。適切な VM を起動するために -client とか -server はランチャ内で利用され、それ以外の引数は JavaVMInitArgs を通じて VM に渡される。
    2. ヒープサイズやコンパイラ種別(client or server)が設定されていない場合、適当な値を設定する。
    3. LD_LIBRARY_PATHやCLASSPATH等の環境変数を設定する。
    4. メインクラスが指定されて居ない場合、jar ファイルのマニフェストファイルからメインクラスを確認する。
  • ContinueInNewThread() [jdk/src/share/bin/java.c]
  • ContinueInNewThread0() [OSによって異なる]
    • non primordial thread を作成、実行する。non primordial thread のエントリポイントは JavaMain()
  • JavaMain() [jdk/src/share/bin/java.c]
    • HotSpot Runtime Overview に記載されている 5. 以降の処理が行われる。
    1. (ContinueInNewThread0() で non primordial thread を作成し、)JNI_CreateJavaVM()を呼んで VM を作成・初期化する。新しいスレッド(non primordial thread)を作成しているのは、この処理自体を行っているスレッド(primordial thread)が、環境によっては色々な制限があり、VMの作成上で制約(Windows上でのスタックサイズなどによる制約など)があるため。
    2. メインクラスを読み込んで、メインクラスからメインメソッドの属性を取得する。
      • LoadMainClass() 以降の処理。メインメソッドを取得しているのは GetStaticMethodID()。
    3. CallStaticVoidMethod() とコマンドラインに渡された引数を使用してメインメソッドを呼び出す。
    4. メインメソッドが完了したら、待機中の例外 (pending exception) がないか確認し、exit status が渡されてないことを確認する。例外は ExceptionOccurred() でクリアされる。メソッドが成功していれば戻り値は 0 に、そうでなければ呼び出し元のプロセスに返却される。
    5. メインスレッドは DetachCurrentThread() によりデタッチされる。これによりスレッドカウントをデクリメントし、DestroyJavaVM() を安全に呼び出し、且つこのスレッドが VM 内の操作やスタック上に Java フレームが存在しないことを保証できる。
      • JavaMain()は最終的に LEAVE() マクロを呼び出し、DetachCurrentThread()、DestroyJavaVM()を呼んでいる。

以上、Launcher 編でした。

JNI_CreateJavaVM() について。

ここは真面目にやると深いので、

まとめ

OpenJDKこわい。

JJUG CCC 2014 Fall で Concurrent Mark & Sweep Garbage Collection について話します。良かったらマサカリを置いて来てね!

JavaOne 2014 で発表してきた。

JavaOne2014JVM 監視・トラブル解析支援ツールである HeapStats について発表してきました。

Session ID: BOF3108
Session Title: Troubleshooting with Serviceability and the New Runtime Monitoring Tool: HeapStats
Venue / Room: Hilton - Continental Ballroom 5
Date and Time: 9/30/14, 20:00 - 20:45

発表スライドは こちら からダウンロードできます。色々と課題も見えた発表でしたが、自分の関わっているプロダクトがあの JavaOne で名乗りを上げ、なおかつ(同時に行った出展なども通じて)好反応を得られたのは感無量でした。
発表や出展の様子は今週末の10/18(土)に行われる JJUG 主催の JavaOne 2014 サンフランシスコ報告会 Tokyo でもう一人のスピーカーが発表する予定です。

もし HeapStats についてコメントや質問、要望などがありましたら メーリングリスト に是非投稿お願いします:) 発表や説明して欲しいなーという方は @sugarlife に Mention ください!ステッカーばらまきに行きます!

JDK 8 新機能ダイジェスト (JDK 8 Features) #java

この記事は Java Advent Calendar 15 日目です!
14日目は @megascus さんの
動的SQLでPreparedStatement+プレースホルダを使用する - 水まんじゅう でした。
明日は @cero_t さんです。

まえがき

いよいよ JDK 8 が来年の3月に正式リリースされます。素晴らしいことに Java Japan User Group の皆様の blog や記事、 JJUG Night、CCC などの勉強会やカンファレンスなど、JDK 8 の新機能が紹介されている場が多いので、既にある程度知っている人も多いのではないでしょうか。しかし、JDK 8 全体としてどのような機能が加わるのか、それを把握する方法がよく解らない人もいらっしゃると思います。ここではどうすれば JDK 8 の新機能を確認できるのか、そして新機能はどう言ったものがあるのか簡単なダイジェストを紹介します。

なお、JDK 8 から導入されるクラスやメソッドは何かという観点での変更点確認は torutk さんの記事に纏まっていますので、そちらを参考に!

JDK Enhancement Proposal

Java 関連の周辺技術標準化は JCP(Java Community Process) によって行われ、新しい技術仕様や改訂仕様(既存技術仕様の改訂)は JSR (Java Specification Request) として提案され、標準化に関する作業が管理されます。
では、JSR を追って行けば JDK の新機能が解るのか?実はそれは違っていて、JDK で何かしらの新機能を加える場合、その内容は JEP (JDK Enhancement-Proposal) として管理されています。JDK 8 の機能部分は、Oracle 社独自の変更(解りやすい例としてFlight Recorder周り)以外の変更点は、OpenJDK 8 プロジェクトの Features から確認できます。今回はこの JEP についてダイジェストをまとめてみました。

JDK 8 Features ダイジェスト

と言うわけでダイジェストです。

126 Lambda Expressions & Virtual Extension Methods

JDK8 の目玉の一つ、Lambda。@bitter_fox さんが素晴らしい発表JJUG CCC 2013 Fallでされたのでそちらを確認しましょう。

138 Autoconf-Based Build System

ビルドシステムの簡素化&並列化を目指して autoconf (./configure style) ビルドセットアップの導入、Makefileのリファクタなど。エンドユーザ(※ここではJava言語を使ってコード書く人)は関係なし。JVMをビルドする人は楽になる(かも)。
個人的にはビルドシステムの改善はどこのプロジェクトでも課題になりやすい感がありますね。

160 Lambda-Form Representation for Method Handles

Lambda関係。メソッドハンドル / invokedynamic の改善。JSR 292の延長。

161 Compact Profiles

Profileの導入。リソースが制限されたデバイスでも動作するように各用途に応じたプロファイルを準備できるようにする。
これは Java ME との統合の一環(JDK8からJava SEとJava MEの統合が目指されている)の拡張。

162 Prepare for Modularization

Project Jigsaw (モジュール化) の前準備。Jigsaw は 元々 JDK 8 からの予定だったが、JDK 9 にずれ込んだ。

164 Leverage CPU Instructions for AES Cryptography

AES暗号化処理の高速化。x86 コアを使っている場合に有効。各環境ごとに対応してる JVM ならではか。

174 Nashorn JavaScript Engine

Nashorn. Rhino 後継の JVM ベースの JavaScript 実装。

176 Mechanical Checking of Caller-Sensitive Methods

セキュリティ関連。エンドユーザは余り関係なし。

179 Document JDK API Support and Stability

Jigsaw、および162:Modularization に関連。JDK APIサポート、及び安定性の文書化。

142 Reduce Cache Contention on Specified Fields

マルチスレッドアプリにおけるキャッシング改善。JVMレイヤの変更で、アプリレイヤは無関係(影響なし)。

122 Remove the Permanent Generation

パーマメント領域の削除。ヒープ領域への統合。
以下、このJEPのソースコードからの確認内容。
PermGenがなくなったので、クラスのアンロードはクラスローダのライフサイクル(破棄)と同期するようになる。
他、UseCompressedKlassPointers が true の場合(追記:デフォルトは環境依存)は、ClassMetaspaceSize(デフォルト100M。指定する場合はKlassEncodingMetaspaceMax以下にしないとUseCompressedKlassPointersが false になる)のMetaspaceを作成する。ここら辺の各種オプション等は、GA 出てから再確認してから別途掲載します。

ソースコード等の情報は以下のように取得する。

173 Retire Some Rarely-Used GC Combinations

テストやメンテナンスコスト削減のため、滅多に使われてない GC 組み合わせを削除。
具体的には

  • -XX:-UseParNewGC -XX:+UseConcMarkSweepGC
  • -XX:+UseParNewGC
  • -Xincgc / -XX:+CMSIncrementalMode

を実行した場合、警告が出力される。

136 Enhanced Verification Errors

JVM's bytecode verifier の拡張。(VerifyError)

148 Small VM

3mb以下のvm作成をサポート。JavaME統合との一貫。

171 Fence Intrinsics

メモリフェンスintrinsics。エンドユーザには影響なし。省略。

153 Launch JavaFX Applications

java コマンドラインから JavaFX アプリがランチできるようになるよ!

103 Parallel Array Sorting

java.util.Arrays に配列をパラレルにソートするメソッド(parallelSort)を追加。JSR 166 (Fork/Join) 関連。

107 Bulk Data Operations for Collections

Lambda関連。ざっくり言うと「filter/map/reduce for Java

109 Enhance Core Libraries with Lambda

Lambda。

112 Charset Implementation Improvements

Charsetの改善。目的はメンテナンス性と性能。

119 javax.lang.model Implementation Backed by Core Reflection

コアリフレクションによるjavax.lang.model実装(読んで字のごとく)。

135 Base64 Encoding & Decoding

Base64 エンコード/デコードの標準APIの提供。

149 Reduce Core-Library Memory Usage

性能に問題を与えない範囲でのコアライブラリによるメモリ消費量の削減。

150 Date & Time API

新たな日付APIの提供。詳細は kis さんの記事が参考になります。また、このAPIの象徴的なツイートは以下の通り。


155 Concurrency Updates

JavaSE5から導入された並行処理用のAPI(java.util.concurrent)の更新。要点は次の三つ。

  • スケーラブルに更新可能な変数(Adder(DoubleAdder、LongAdder等)、Accumulator(DoubleAccumulator、LongAccumulator等))の追加
  • ConcurrentHashMap に対するキャッシュ指向の機能拡張(メモリ消費削減、シーケンシャル・並行処理のサポート)
  • ForkJoinPool の改良(パフォーマンス改善など)
170 JDBC 4.2

JDBCのマイナー拡張。

177 Optimize java.text.DecimalFormat.format

DemicalFormatの最適化。ゴールは2倍の速度改善らしい(micro-benchmark)。

178 Statically-Linked JNI Libraries

statically linked native librariesのサポート(JNI)

180 Handle Frequent HashMap Collisions with Balanced Trees

java.util.HashMap のパフォーマンス改善。バランス木による頻繁な HashMap 衝突のハンドリングによって改善を図る。

184 HTTP URL Permissions

IPアドレスレベルに基づいたHTTP URLパーミッションの追加。

185 JAXP 1.5: Restrict Fetching of External Resources

JAXP 1.5の更新。メインは外部リソース取得の制限。

core/lang 関連の JEP

以下の JEP により、言語(主にアノテーションJavaDoc絡み)に変更が入りました。

  • 101 Generalized Target-Type Inference
  • 104 Annotations on Java Types
  • 105 DocTree API
  • 106 Add Javadoc to javax.tools
  • 117 Remove the Annotation-Processing Tool (apt)
  • 118 Access to Parameter Names at Runtime
  • 120 Repeating Annotations
  • 139 Enhance javac to Improve Build Speed
  • 172 DocLint
core/i18n 関連の JEP

国際化に関する変更は、主に Unicode 6.2 がサポートされたことがメイントピックだと思われます。

  • 127 Improve Locale Data Packaging and Adopt Unicode CLDR Data
  • 128 BCP 47 Locale Matching
  • 133 Unicode 6.2
core/sec 関連のJEP

セキュリティ関する以下の機能がサポートされました。新たにサポートされた暗号化方式は何かを知りたい場合は、JEP 115: AEAD CipherSuites を確認しましょう。

  • 113 MS-SFU Kerberos 5 Extensions
  • 114 TLS Server Name Indication (SNI) Extension
  • 115 AEAD CipherSuites
  • 121 Stronger Algorithms for Password-Based Encryption
  • 123 Configurable Secure Random-Number Generation
  • 124 Enhance the Certificate Revocation-Checking API
  • 129 NSA Suite B Cryptographic Algorithms
  • 130 SHA-224 Message Digests
  • 131 PKCS#11 Crypto Provider for 64-bit Windows
  • 140 Limited doPrivileged
  • 166 Overhaul JKS-JCEKS-PKCS12 Keystores

まとめ

以上、JDK 8 新機能のダイジェストでした!いかがでしたでしょうか、意外にこんな機能も追加されていたんだなーとか何かの気付きになれたら幸いです。
個人的には「 JEP 122: Remove the Permanent Generation 」と「 JEP 155: Concurrency Updates 」はその内もっと掘り下げていくことになりそうです。

Groovy で JVM ログ解析 (ClassHistogram編) #gadvent #java

Groovy で 面倒な JVM ログを解析する (ClassHistogram)

前置き

この記事はG*(Groovy, Grails ..) Advent Calendar 2013 - Qiita [キータ]の10日目です。
前日は研究室の先輩 @tetsurokitaharaさんのGracenote with Groovy でした。

JVM(hotspot) は好きですが Java は余り書かず、作りこむなら Scala、速度が欲しいなら C、ログの解析なら awk/sedRuby 等で済ます日々ですが、Java のログなので Groovy でさっと処理してしまおうと考え取り組んでみました。どうせなので groovysh で扱える仮想配列として出力し、後々好きな様に加工できるようにしました。
この題目は7日目の@nobusueさんのGroovyでGCログ解析と多少被ってますが、別のログが対象ということで許してください><

JVM ログで出力される ClassHistogram とは

一般的には OutOfMemoryError が発生した場合などで利用するクラス統計情報で、現在実行中の Java プロセスに存在する各クラスのインスタンス数、バイト数が含まれています。
JVM 起動オプションに -XX:+PrintClassHistogram を指定し、SIGQUIT (kill -3 ) を送出すれば以下のようなログが出力されます。

num   #instances    #bytes  class name
--------------------------------------
  1:     24868     3398080  <no name>
  2:     24868     2598976  <methodKlass>
  3:      2813     2432352  [I
  4:      1970     2415680  <constantPoolKlass>
  5:      1970     1873040  <instanceKlassKlass>
  6:      1873     1661760  <constantPoolCacheKlass>
(中略)
1105:         1          16  sun.reflect.GeneratedMethodAccessor3
1106:         1          16  sun.awt.X11.XProtocol$1
Total   172945    22390368

これを間隔を置いて複数回出力させれば、各クラスが時系列にそってどのように増減しているかが調べることが可能です。解りやすい例だと、あるクラスのバイト数が常に増大していれば、明らかにそのオブジェクト(を生成している部分)でメモリリークを起こしてることが判明します。
このログで面倒なのは、複数クラスローダが存在する場合です。クラスローダAとクラスローダBで同じクラスがロードされていると、それは別物扱いなので同じクラス名の情報が重複して出力されます。その上このログからはクラスローダ情報はばっさり捨てられてるので、今回は同じものとして加算しています。

ログから各クラスの時系列ごとの統計情報を解析する

というわけで仮想配列を出力するコードです。実は何気に殆ど初 Groovy だったりするので所々酷いところがあると思います。。

一枚目の gist のコードを保存し、二枚目の gist の通り groovysh で呼び出して仮想配列として出力できます。その後は、例えば以下のようにすればクラス一覧を出力しつつ、各自系列ごとのランク、インスタンス、バイト数情報が引き出せます。

import static ClassHistrogram.*
ch = calc("*log")
ch.each{ klass, timeline ->
  println "{${klass}:"
  timeline.each{ time, value ->
    println "  {${time}:{rank:${value[0]},instance:${value[1]},byte:${value[2]}}}"
  }
  println "}"
}

---出力例---
{sun.java2d.pipe.LoopPipe:
  {0:{rank:1040,instance:1,byte:16}}
  {1:{rank:1057,instance:1,byte:16}}
  {2:{rank:1071,instance:1,byte:16}}
  {3:{rank:1079,instance:1,byte:16}}
  {4:{rank:1079,instance:1,byte:16}}
  {5:{rank:1081,instance:1,byte:16}}
  {6:{rank:1082,instance:1,byte:16}}
  {7:{rank:1079,instance:1,byte:16}}
  {8:{rank:1078,instance:1,byte:16}}
  {9:{rank:1078,instance:1,byte:16}}
  {10:{rank:1078,instance:1,byte:16}}
}
---

このように LTSV 形式に出力するのもよし、CSV ファイル形式に出力や特定クラスの情報だけ引っこ抜くのも良しで、加工しやすいのではないかと思います。

以上です、次は https://twitter.com/setoazusa:title@setoazusa さんの番です!

「Java解析ツールバトル」に登壇しました & HeapStats の動かし方について #jjug

JJUG ナイト・セミナー 「Java解析ツールバトル」に HeapStats 陣営でコミッターとして参加してきました!

今回のJJUGでは、自分達の JVM に深く密着してパフォーマンスに心血を注いでいる HeapStats、最近 OSS 化された Java だけでなく SQL 実行計画まで総合的に診断する EndoSnipe、昨日の OracleJDK 7u40のリリースで公式に JDK に付属された Java Flight Recorder と twitter4j の開発者であるモデレータが過去に開発された 侍 の三つ巴でディスカッションを行いました。
数々のプロジェクトやサービスで利用されている Java だからこそ、障害や性能問題に悩まされる人の数も多いと思われます。障害解析の手助けになるツール、それも今回参加した3つの内2つは日本人によって開発されていることもあり、かなりの盛況ぶりだったと思います:)

自分達のHeapStatsの発表資料はSlideshareで公開しています。興味のある方はぜひご覧ください。


ディスカッションでは時間の関係上、駆け足での説明だったため、「HeapStats はどうやって動かすの?」という最初の一歩をもう少し詳しく補足していきたいと思います。

HeapStatsのインストール

HeapStats インストール条件

性能に心血を注いだ結果として、JVMに手を突っ込み、一部のコードをアセンブラ化している等が原因で、HeapStatsを動かすためには以下の環境である必要があります

  • HotSpotであること
    • OpenJDK 6以降, あるいは OracleJDK 6以降
    • OpenJDK の場合は debuginfo パッケージもインストールする必要があります。
  • x86 または AMD64Linux であること
HeapStats インストール&動作方法

HeapStats をインストールするためにはバイナリからインストールする方法と、ソースからビルドする方法があります。今回はバイナリからインストールする方法を紹介します。

  • バイナリをここから取得してインストールする。
    • $ rpm -ivh heapstats-agent-[version].[CPU命令セット].[Linux dist].[アーキテクチャ].rpm
    • CPU命令セットの部分は解らない場合は何も記載されていない物を利用して下さい。
      • 利用している環境がサポートしているCPU命令セットを確認したい場合、"/proc/cpuinfo" の "flags" を見ることで確認ができます。
      • avxが書かれている場合はavxを、avxはないがsse4が書かれている場合はsse4を、それ以外は無印を利用するのがお勧めです。
    • Linux dist の fc は Fedora, el は RedHat Enterprise Linux を指します。
  • 監視させたい Java プログラムの起動オプションに以下を追加して実行する。
    • -agentlib:heapstats
    • 既に動作している Java プロセスに対してアタッチする場合は こちら を確認して下さい。
  • 実行ディレクトリに heapstats.csv, heapstats.dat が出力される。
    • analyzer を利用して可視化が行えます。
    • 出力フォルダは設定ファイル /etc/heapstats/heapstats.conf (デフォルト) を編集することで変更できます。

以上で HeapStats は実行している Java プロセスを常時監視しつつ各種情報を取得し、故障発生時には解析に必要な情報を根こそぎ取得するようになります!

HeapStatsの各種設定やアナライザによる可視化は公式サイトをご確認下さい。日本語サイトも準備されています!