クラスローダリークとヒープダンプ
Java EE を使っている人なら多くの人が遭遇するクラスローダリーク。EclipseなどのIDEでホットデプロイしながら開発していると、突然APサーバから応答がなくなったり、java.lang.OutOfMemory : PermGen
が出力されたりする。
原因についてはnekopさんのスライドやyamadanさんのブログに紹介されているので、ここではクラスローダリークを手元で再現させてみて、どのようなヒープダンプになるか紹介する。
ヒープダンプの解析にはEclipseMemoryAnalyzer(MAT)を使う。
1. Duplicate Classes を確認する
クラスローダリークが発生している状況では、同一のクラスが異なるクラスローダよりロードされている事象が起こっている。MATでは重複クラスロードの一覧を表示する機能があるため、1クリックで確認できる。
2. Paths to GC Roots の確認
ここまででクラスローダリークかどうかを識別したが、原因がわからない。何が原因でGCされていないかは、対象のクラスローダインスタンスを選択して右クリックし、Path to GC Rootsを確認する。
以下のように、TomcatのプールされているTaskThreadが持つThreadLocalから参照されてGCされないことがわかる。
WildFly8でも同様に、プールされているスレッドのThreadLocalから参照されてGCされないことがわかる。
ThreadLocalにユーザ情報などリクエスト共通で使いたいデータを格納した後、ThreadLocal.remove()
を実行せずにAPサーバのプールにスレッドを返す、よくあるクラスローダリークの原因例を示したヒープダンプでした。ServletFilterなどを使ってタスクスレッドがAPサーバのプールに返る前にThreadLocal.remove()で掃除することが大切です。