unnamed

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

G1 GC おさらいと #jjug_ccc で発表した話

この記事は Java Advent Calendar 2015 の一日目の記事です。二年連続でトップバッターだ!

先日の JJUG CCC 2015 Fall で G1 GC について話してきました。
去年の CMS GC と同じく結構遅めの時間帯&裏番組に伝説の灰色ページ管理人・ひしだま伝道師が発表するなどの豪華な時間帯にも関わらず、165人規模の部屋がいっぱいに埋まるぐらいの盛況でした。聴講頂いた皆様ありがとうございました!
スライドは以下に公開しました。G1 GC の挙動から GC ログの読み方、どういうケースが厄介なのかを紹介しているので是非ご覧ください!

アフターフォロー、またはちょっとした補足

極力、後から参照可能なように資料を作っていますが、どうしても口頭で補っている部分はあります。
セッションのハッシュタグである #ccc_cd6 で Twitter 検索した結果 なども合わせてご確認ください。

一般的な注意事項について
  • JDK9 から G1GC がデフォルト化されます。JDK9 を導入される際は使用する GC を明示的に指定することをお勧めします。
  • ヒープサイズが小さい環境で G1 GC を選択する際は注意してください。元々ヒープサイズが巨大な環境のために開発されたものなので、ヒープの使用「率」(-XX:InitiatingHeapOccupancyPercent) が比較的低い段階から活発に GC が実行されるなど、本来のメリットがデメリットとして襲い掛かってくることがあります
オプションについて
  • CMS GC と同様に -Xmx と -Xms は同じ値にしたほうが、拡張/シュリンク時のコストが発生しないのでお勧めです。
  • オプションで Young 領域(Eden、Survivor 空間)のサイズは指定しないほうが性能が良いケースがあります。これは Young 領域のサイズを設定しない場合は状況に応じて JVM が動的に変更するため、人間が決め打ちでやるより効率が良くなるパターンが往々にしてあるからです。
  • -XX:MaxGCPauseMillis は STW の時間を指定するものではありません(主にマーキングサイクルのコンカレント部分に効く)
検索して引っかかる古い情報について
  • 以下のスライドの Mixed GC の処理条件が最近のアップデート(JDK-8059452, JDK8 update 40)で、緩めなOld 領域をより徹底的に回収する条件に変更されてます。JDK9 でデフォルト化の話がこの辺りで出てきたので、それに前もって導入された印象です。
    • G1MixedGCLiveThreshold が 65 から 85 に変更
    • G1HeapWastePercent が 10 から 5 に変更
    • 追記 2015/12/1 12:40 @den2sn さんよりコメント頂き表現を修正。合わせてスライドも表現が誤っていたので修正。

  • 以下のスライドの Evacuation Failure が発生した際、次のページに書かれてるようにログに (to-space exhausted) という文字列が出力されます。しかし、 Oracle のドキュメント等によると (to-space overflow) と出力されるバージョンもあるようです。今回の発表スライド作成時に確認したソースコードにはそういう文字列はありませんでした。古いバージョンを利用する場合はこの文字列も注意してください。

伝えたかったこと

これまで 渋谷Java で OutOfMemoryError の話をきっかけに、JJUG CCC 2014 Fall で CMS GCJava 女子部で JVM のいろは、そして今回の G1 GC の話をしてきました。これらの発表の原動力は去年の夏の JJUG ナイトセミナー LT 大会でした「楽して JVM を学びたい」という発表が大元です。

勉強するためには、体系だった知識が下敷きにあるとないとで理解の差が段違いです。特に自分は難聴者なので、分かりやすい資料や書籍があるかが大きな差となりました。なるべく JVM の勉強をしてみたいという人に向けて、特に問題になりがちなメモリ管理の分野に関して、実際のトラブルで役に立つ知識を中心に、後から読み返してもスッと入ってこれる体系だった丁寧な資料作りを心がけてきました。

これまで OpenJDK のソースコードを読み、数々のそれなりにタフなトラブルシュートを駆け抜け、たまに OpenJDK パッチを書いて投稿しという活動を繰り返してきました。いまだにコミッターどころか Author にもなれてませんが、自分なりに Java のコミュニティに貢献できればと思い発表してきました。どこかの誰かの「楽して JVM を学びたい」という気持ちに答えられていたら幸いです

www.slideshare.net

www.slideshare.net
www.slideshare.net
www.slideshare.net
www.slideshare.net

おまけ

最終回っぽい〆をしてますが、別に Java はやめません :p

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

JJUG ナイト・セミナー 「ビール片手にLT&納涼会」で、来年出る予定のJDK9の新機能(2015/7/31時点)について喋ってきました。JDK9の機能が全て出揃う(Feature Complete)のは 2015/12/10 ですが、これから大量に出てくるのも考えにくいので LT の時点で出ている分をまとめました。

JDK8 で導入された機能についても過去にまとめてあります

新たな JDK で導入される機能について

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

発表資料

以下、JDK9 新機能のダイジェストです、ご査収ください

以下の英語版はもうちょっとだけ詳しく書いてます

LT 時は五分でおさまるように練習したのに、遅刻気味で全力疾走からの飲酒を決めて酔っ払い、5分で喋りきれませんでした。すみません(・ω<)てへぺろ

JDK9 の影響

それぞれで影響が大きい機能は異なってきますが、以下の機能は多くのプロダクトに影響が大きいかもしれません。

  • Project Jigsaw (JEP 220、他)
    • sun.* パッケージの扱い (JEP 193、他)
  • JVM ログ統一 (JEP 158)
  • G1GC デフォルト化 (JEP 248)

個人的には P.12 にまとめた sun.misc.Unsafe の動向が超重要(JDK内部でも使ってるし即消えることはないとは思いますが…)で、G1GC リプレース型の新 GC (Shenandoah) どこ行ったという所感です。

「Java パフォーマンス」感想

本書の翻訳者の一人である@cero_tより献本頂きました、ありがとうございます。というわけで一週間かけて読んでみた。

www.amazon.co.jp

今現在 Java で開発している人、特に運用者や試験者は間違いなく買っておくべき本です。Javaに限らない一般的なパフォーマンスチューニングの考え方・観点から、Java アプリケーションにおいてボトルネックになりやすい GCJIT の詳細な確認方法からチューニング方法が解説されている。特にすごいのが Java の世界のみならず、OS の世界まで触れている点。流石に OS の世界はここに書かれているのが全てではないけれど、Java アプリに関わる部分で問題になりやすい点は割と触れている。

JDK8 にも対応しており、今現在手に入る情報としては一番頼もしいと思う。4000 円程度でこの知識量が手に入るなら非常に安い。

お勧めの読み方

個人的にお勧めの読み方はパフォーマンスの観点やツールの使い方が書かれている 1-3 章は誰でも先ず読んでおき (3.4 は HeapStats でも良いよ!)、使っている GC アルゴリズムに合わせて GC について書かれている 5-6 章を読むのがお勧めです。GC ログの読み方から解説されているので、今現在で問題が出てないかの確認も行えるのが便利。CMS GC に関しては拙作のスライドもあわせてどうぞ。

Java で今まさにコーディングしている人は 9,12 章でコーディングにおける効率的な書き方を学びつつ、メモリ使用状況をどう確認するべきか 7-8 章 で学ぶのが良さそう。これらの章以外もちょくちょく読み進めておき Java の世界(JITとか)と Java を取り囲む世界でどのように確認すべきか少しずつ観点を増やしていけます。

この本の凄いところ

この本でサポートできないのは、よりコアな一般的でないチューニング(大抵稼働がかかり過ぎるのでやるべきではない)や、JVM の実装に依存する内容(バグとか)、JNI や sun.misc を利用した黒魔術コーディング、よりハードウェアを意識したコーディング/チューニング等なので、基本的にこの本に書かれている内容を実践するだけで大方の運用面における問題は解決するか、解決の糸口が掴めると思います。

コアな一般的でないチューニングとは言うけれど、この書籍のように Large Page や TLB キャッシュ率、オブジェクトのロックコストなどに一冊で言及した書籍なんてそうそうありません。特に GC でどういった状況が発生したら問題で、その解決方法(チューニング)を割と網羅しており、各種ランタイム情報の確認方法まで書かれているので、この本で解決しないなら結構な経験者や OpenJDK に詳しい人を引っ張りださないと辛いと思う。

ちなみに CMS GC の注意すべきケースとして promotion failed というのがありますが、これは「昇格の失敗」という日本語になっていました。訳としては正しいのですがログには promotion failed と出ますが、その単語からは索引できないので注意が必要です。

おわりに

日本語でこのレベルを読めるようになったのは便利だなあ。数年前からJavaメモリモデルを意識したコーディングや、ハードウェアを意識したチューニングが JavaOne とかで発表されてましたが、より多くの所がその水準に行くための土台ができてき始めてるかもしれませんね。

(´-`).oO(新人教育や知識継承、この本読めば済みそう)

How specify JVM options by file.

Use -XX:+Flags=<file>. You can specify *ONLY* "-XX" options.


OpenJDK checks this option when vm parses the arguments as following.

Crypt 200: Decrypt it(Easy)

ctpm として SECCON 2014 オンライン予選(en) に出ました。25位でした。

上記事の Decrypt it(Easy) を途中から一緒にやりつつ後を引き継いだのに、アホなミス('A')で取りこぼしたので、終了後に解き直したスクリプトを覚え書きとして残す。

なお、「Sage - Open-Source Mathematical Software System」を使っている。

#! /usr/bin/python
# -*- encoding: utf-8 -*-

from sage.all import *

def decode(target):
  if len(str(target)) % 2 == 0:
    print str(hex(target)).decode('hex')

for n,b,c in ([0xb8ae199365,0xffeee,0x8d5051562b],
    [0xb86e78c811, 0xfffee, 0x5ffa0ac1a2], [0x7bd4071e55, 0xfefef, 0x6008ddf867]):
  p,q = map( lambda x : x[0], factor(n) )

  for x in range(p):
    if (x*x + b*x - c) % p == 0:
      x_p = x
      #break
  for x in range(q):
    if (x*x + b*x - c) % q == 0:
      x_q = x
      #break

  decode( crt(x_p, x_q, p,q) )
  decode( crt(p-b-x_p, x_q, p,q) )
  decode( crt(p-b-x_p, q-b-x_q, p,q) )
  decode( crt(x_p, q-b-x_q, p,q) )
  print "-" * 16

実行結果は以下の通り

# sage -python solver.py
SECCO
aNウq
    eh(
W_V"
----------------
2_5
N{Ra_
V
if
  ----------------
b1_N}
U4

%2
----------------

Rabin暗号単射じゃないので一意ではない。意味ある文字は SECCON{Ra_b1_N} ですね。

コアダンプから Java 起動オプションの抜き出し方

この記事は JVM Advent Calendar 2日目 の記事です。

JVM を触っているとコアを吐いて落ちる事がしばしばあります。ええ、しばしばあります。
こういう時にどのようなオプションで起動していたかをうっかり忘れると後々面倒です。
でも、実は簡単に解ります。

簡単なやり方

# strings core.12672 | grep -- -Xmx
-XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly -Xmx1500m -Xms1500m -Xloggc:gc.log -XX:+PrintGCDetails -XX:+CMSClassUnloadingEnabled

-Xmxを指定していないときは -XX: とかで grep すると引っ掛かります。

JVM に興味があってちゃんと取りたい人向け

Arguments::_jvm_args_arrayJava 起動オプションを格納した配列で、Arguments::_num_jvm_args がこの配列長(Java 起動オプションの数)です。この静的メンバ変数らはコアダンプが出力された時も存在しています。
なので、gdb で、この配列から要素を引っこ抜いてやれば全 Java 起動オプションが取れます。

たとえば、コアを gdb で起動して以下のコードを実行させれば全 Java 起動オプションが表示されます。

set $num = Arguments::_num_jvm_args
set $i = 0

while($i < $num)
  x/a Arguments::_jvm_args_array + $i
  x/s $__
  set $i++
end

※:バージョンによってはシンボル名が違ったりマングリングされてたりで、Arguments::_num_jvm_args が _ZN9Arguments13_num_jvm_argsE になってたりする場合もあります。

実証 (上のコードを test.gdb として保存しておく)

# java -Xmx100M -Xms100M -XX:+UseConcMarkSweepGC -Xloggc:gc.log -XX:+PrintGCDetails -XX:+CMSClassUnloadingEnabled Test &
[1] 12672
# gcore -o ./core 12672()
Saved corefile ./core.12672
# gdb /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.25.x86_64/jre/bin/java-abrt core.12672 < test.gdb()
gdb-peda$  > > > >
0x7fbd80003120: 0x7fbd80003050
0x7fbd80003050: "-Xmx100M"
0x7fbd80003128: 0x7fbd80003070
0x7fbd80003070: "-Xms100M"
0x7fbd80003130: 0x7fbd80003090
0x7fbd80003090: "-XX:+UseConcMarkSweepGC"
0x7fbd80003138: 0x7fbd80003030
0x7fbd80003030: "-Xloggc:gc.log"
0x7fbd80003140: 0x7fbd80003100
0x7fbd80003100: "-XX:+PrintGCDetails"
0x7fbd80003148: 0x7fbd800030b0
0x7fbd800030b0: "-XX:+CMSClassUnloadingEnabled"
gdb-peda$ quit

おわりに

strings の方が楽でしたね!僕は gdb スクリプト書いてから気付きましたばーかばーか!(つД`)・゚・