java.lang.OutOfMemoryError #渋谷java

32
yright(c)2014 NTT Corp. All Rights Reserved. java.lang.OufOfMemoryError <3 NTT OSS Center KUBOTA Yuji @sugarlife 1 渋渋 Java

description

#渋谷java 発表資料です。

Transcript of java.lang.OutOfMemoryError #渋谷java

Page 1: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

java.lang.OufOfMemoryError<3

NTT OSS Center

KUBOTA Yuji

@sugarlife

1

渋谷 Java

Page 2: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

Disclaimer

本資料は以下の JDK を基に記載しています 1040:4095a7a49a9e (jdk8u20-b15)

http://hg.openjdk.java.net/jdk8u/jdk8u

880:19a3f6f48c54 (jdk7u60-b15) http://hg.openjdk.java.net/jdk7u/jdk7u ※ : JDK7 と記載がある場合のみ

特に明記がない場合 , デフォルト値は LP64でのデフォルト値を記載しています。

2

Page 3: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

KUBOTA Yuji

IcedTea コミッタ (HeapStats) OpenJDK(icedtea) のサポートしています その他

CTF newbie (ctpm, etc) twitter: @sugarlife 難聴なので右耳しか聞こえません。

3

Page 4: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

Agenda

今日やる事 java.lang.OutOfMemoryError に , 遭遇した

際の心構えを覚える 今日やらない事

Garbage Collection Exception Mechanism Java Memory Model

4

Page 5: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

java.lang.OutOfMemoryError

メモリ不足になった際に発生 Exception ではなく Error

その後の挙動は一貫性のない不定状態 情報を取ったらすぐ殺そう

-XX:+HeapDumpOnOutOfMemoryError -XX:OnOutOfMemoryError=‘/bin/kill -ABRT %p’ HeapDump を取得してから

OnOutOfMemoryError で指定されたコマンドが実行されます。

5

Page 6: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

Metaspace

Java におけるメモリ構成(ここでの定義)

OOME が発生したらどこを見ていくべきか。

Java heapPermanentnativeThreadStack

-Xmx-XX:MaxPermSize

OS

-XX:MaxMetaspaceSize

-Xss*threads

Compressed Class Space

-XX:CompressedClassSpaceSize

JDK7 以前

※ 注:この図は解りやすくするために一部嘘をついています。 例: Metaspace は不連続。 Permanent は一部 heap にも移動した。

ThreadStack は 1 スレッド辺り Xss + guard page サイズ , 等。

6

OS 管理 JVM 管理 JVM,JNI コードデータセグメント等

JDK8

Page 7: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

OutOfMemoryError = heap ?

java.lang.OutOfMemoryError: Java heap space

7

OOME のありがちな誤解

Page 8: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

OutOfMemoryError(s) Java heap space GC overhead limit exceeded could not allocate Unicode string PermGen space Metaspace Compressed class space unable to create new native thread Requested array size exceeded Could not map PerfMemory Failed to reserve memory, etc… 8

Page 9: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

OutOfMemoryError(s) Java heap space GC overhead limit exceeded could not allocate Unicode string PermGen space Metaspace Compressed class space unable to create new native thread Requested array size exceeded Could not map PerfMemory Failed to reserve memory, etc… 9

heap

non-heap

native

それ以外

Page 10: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

OOME cause

発生条件 解決方法

次ページ以降のスライドの読み方

10

Page 11: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved. 11

Native

Metaspace

Java heapPermanentnativeThreadStack

-Xmx-XX:MaxPermSize

OS

-Xss*threads

Compressed Class Space

JDK7 以前

JDK8

-XX:MaxMetaspaceSize

-XX:CompressedClassSpaceSize

Page 12: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

unable to create new native thread (1)

スレッド作成時に OS のメモリ不足か ,VMA(※) 等の制限に到達した。 JVM は glibc が提供する pthread_create() を使って

スレッドを作成している。

スレッド数かメモリ不足か確認して対処する。 メモリ不足の場合

procfs(/proc/<pid>/status) の VmHWM や free 等で確認。

メモリの増設か , Xss を小さくして ThreadStack 領域を圧縮して対応。 ( デフォルト 1m)

32bit の場合は、プロセス全体で約 4G 程度が限界であることに注意。 12

※: 読み書き権限やファイルマップ有無などの属性が同じで仮想アドレスが連続する仮想メモリのこと。

Page 13: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

unable to create new native thread (2)

スレッド数かメモリ不足か確認して対処 ( 続 ) スレッドを大量に作成している場合

JMX や jconsole, jstack 等でスレッド数を確認する。

設定例: Linux で 10 万個 ( バッファ 1 万 ) のスレッドを作成したい場合。 echo 110000 > /proc/sys/kernel/threads-max

echo 110000 > /proc/sys/kernel/pid_max

echo 220000 > /proc/sys/vm/max_map_count

/proc/<PID>/limits の Max processes を 110000 にする。

素直にスレッドプールを利用して実装する。13

Page 14: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved. 14

Metaspace

Java heapPermanentnativeThreadStack

-Xmx-XX:MaxPermSize

OS

-Xss*threads

Compressed Class Space

JDK7 以前

JDK8

heap + non-heap

-XX:MaxMetaspaceSize

-XX:CompressedClassSpaceSize

Page 15: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

GC overhead limit exceeded GC が頻発して時間的な閾値を超えた

-XX:GCTimeLimit で設定した , JavaVM 走行時間に占める GC 処理時間を超えた場合。 ( デフォルト 98%)

-XX:GCHeapFreeLimit で設定した以上の Old 世代の空き領域確保できなかった場合。 ( デフォルト 2%)

GC が実行されてもアプリに必要なメモリが不足しているのが原因。 後述する Java heap space と non-heap の

対処を行う。 メモリ使用量ギリギリを攻めるコードで再現可

能15

Page 16: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

could not allocate Unicode string

Interned String をアロケートしようとした際に OOM JDK8 で導入

http://hg.openjdk.java.net/hsx/hsx25/hotspot/rev/f258c5828eb8

OOME 投げる処理がなかったため , クラッシュしてたのを修正

Interned String が格納される領域にあわせて対策を行う JDK6 では PermGen, JDK7 以降は heap 現状では、 JDK8 のみなので heap に注意する。

16

Page 17: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved. 17

Metaspace

Java heapPermanentnativeThreadStack

-Xmx-XX:MaxPermSize

OS

-Xss*threads

Compressed Class Space

JDK7 以前

JDK8

non-heap

-XX:MaxMetaspaceSize

-XX:CompressedClassSpaceSize

Page 18: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

Compressed class space / Metaspace / PermGen space (1)

大抵の場合、次の 2 種。実測が必要。 JVM にロードされる総クラスサイズの見積もりミス。

動的クラス生成や、システムクラスの見積もり不足など クラスローダに関連するメモリリーク。

@nekop さんの「 ClassLoader Leak Patterns」参照。

各メモリ必要量を測定して設定値を変更する。 Metaspace: -XX:MaxMetaspaceSize

デフォルト:青天井 ((uintx)-1) Compressed class space: -

XX:CompressedClassSpaceSize デフォルト :1G (過去の類似設定では 100M)

PermGen space: -XX:MaxPermSize (JDK7:64M)18

Page 19: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

Compressed class space / Metaspace / PermGen space (2)

19

測定方法 デフォルト設定で負荷試験を行い、 HeapStats か

GC ログで最大サイズを測定する。 -XX:+PrintGCDetails によって表示される。 [Metaspace: GC 前のサイズ ->GC 後のサイズ… ] ※ 注: Compressed class space も含まれたサイズです。

その他の測定方法 @YaSuenag さんの「 MetaspaceをOpenJDK

実装から見てみよう!」 Metaspace で困ったらここを見れば解決。

Page 20: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved. 20

Metaspace

Java heapPermanentnativeThreadStack

-Xmx-XX:MaxPermSize

OS

-Xss*threads

Compressed Class Space

JDK7 以前

JDK8

heap

-XX:MaxMetaspaceSize

-XX:CompressedClassSpaceSize

Page 21: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

Java heap space (1) インスタンス作成などで -Xmx で指定した

以上のヒープを利用しようとした メモリリークかメモリ不足

ログから調査 @n_agetsu さんの「 Javaトラブルに備えよう」 GC ログ (-X:loggc:<path>, -XX:

+PrintGCDetails) Major GC / Full GC 直後のヒープサイズを確認。 長時間に渡り単純増加している:リークしている? 突発的に増加して OOME が発生:メモリ不足?

21

Page 22: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

Java heap space (2)

ログから調査(続き) OOME 直後の状況をヒープダンプから分析

-XX:+HeapDumpOnOutOfMemoryError Eclipse Memory Analyzer などでの解析がお勧め

インスタンス占有状況を時系列で確認 クラスヒストグラムを定期的に取得、整形して確認。 -XX:+PrintClassHistogram & 定期的に kill -3

<pid> jmap や jcmd でも可能。

面倒なので HeapStats でまとめてやる22

Page 23: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

HeapStats NTT OSS センタで開発& OSS化

トラブルシューティングに必要なログを余さず取得するのが目的

http://icedtea.classpath.org/wiki/HeapStats/jp

利用方法 rpm –ivh heapstats_agent_*.rpm -agentlib:heapstats を追加 実行ディレクトリにログ出力される

Demonstration23

Page 24: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

HeapStats – thread の確認

24

定期的に取得して heapstats_log.csv に保存される。

デモの様子

Page 25: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

HeapStats – non-heap の確認

25

FullGC ごとに取得して heapstats_snapshot.dat に保存される。 PermGen も同様に表示可能です。

デモの様子

Page 26: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

HeapStats – heap の確認 (1)

26

FullGC ごとに取得して heapstats_snapshot.dat に保存される。 GC 時間も合わせて表示されます。このままだとリークの根本原因は不明のまま。

デモの様子

Page 27: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

HeapStats – heap の確認 (2)

27

各クラスごとのサイズも時系列で表示される。これを見ると青色 ([B) のクラスが明らかにリークしている。

デモの様子

Page 28: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

HeapStats – heap の確認 (3)

28

クラスの参照関係をサイズ順に確認できる。リーク原因と思わしき [B( バイト配列 ) は Air クラス等と参照関係があるので , これらのクラスで作成されている可能性がある。サードパーティ製を含めて調査範囲を絞れる

デモの様子

Page 29: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved. 29

それ以外

Page 30: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

Requested array size exceeds VM limit

new Object[Integer.MAX_VALUE] Refactoring

Collection API を使いましょう。(e.g. ArrayList)

富豪プログラミング怖い

30

Page 31: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved.

Could not map PerfMemory hsperfdata からマッピングができない

Java プロセスは , テンポラリ領域 ( 例 :/tmp) /hsperfdata_ユーザ名 ディレクトリに一時ファイルを作成する。

jps や jstat はこのファイルを参照して , 監視Java プロセスのアドレス空間を自プロセスにマッピングする。この時にこけてる。

JVM と jps/jstat が 32bit/64bit で異なるとか。 Java バイナリを統一する , hsperfdata の所

有権を確認する。ビット違いによるエラーは JDK6 で修正済み

31

Page 32: java.lang.OutOfMemoryError #渋谷java

Copyright(c)2014 NTT Corp. All Rights Reserved. 32

Question?