unnamed

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

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(新人教育や知識継承、この本読めば済みそう)

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 スクリプト書いてから気付きましたばーかばーか!(つД`)・゚・

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 との付き合いはしばらく続きそうです。