ClassLoader Leak Patterns

11,091 views

Published on

Published in: Technology
0 Comments
26 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
11,091
On SlideShare
0
From Embeds
0
Number of Embeds
622
Actions
Shares
0
Downloads
103
Comments
0
Likes
26
Embeds 0
No embeds

No notes for slide

ClassLoader Leak Patterns

  1. 1. クラスローダ リークパターン なにそれおいしいの? Takayoshi Kimura Senior Software Maintenance Engineer, JBoss Global Support Service Red Hat
  2. 2. 自己紹介
  3. 3. nekop ● JBoss の中の人 ● Emacs で Java 書く人 ● オープンソース大好きっ子 ● ネコよりイヌが好き
  4. 4. 宣伝
  5. 5. JBoss では エンジニアを 募集して おります!
  6. 6. JBoss で働きませんか ● Java とオープンソースが好き な人におすすめ ● おやつ無料 ● 飲み物自動販売機無料
  7. 7. JBoss で働きませんか ● 主に「オープンソースで遊ぶ」 のと「技術的な人助け」 ● Linux カーネルから Java アー キテクトまで豊富な同僚
  8. 8.  本題 
  9. 9. クラスローダ リーク
  10. 10. 何が起こる? ● java.lang.OutOfMemoryError: perm gen space ● クラス定義情報が置いてあるメ モリ領域 (Perm) を消費しっぱ なし
  11. 11. いつリークする? ● クラスローダが破棄、再作成さ れるタイミング ● 具体例として、アプリケーショ ンサーバに再デプロイを行った とき
  12. 12. なぜリークする? ● そのクラスローダへの参照が 残ってるから ● そのクラスローダからロードさ れたクラスへの参照が残ってる から ● クラスローダをまたがる参照
  13. 13. パターン その1 ThreadLocal
  14. 14. ThreadLocal ● 同一スレッド上で値の受け渡し ができて便利 ● フレームワークなどでよく使わ れている
  15. 15. ThreadLocal の参照構造 ● ThreadLocal に設定した値は Thread から強参照される ● 詳しく知りたい人はソース嫁
  16. 16. ThreadLocal 開放条件 ● ThreadLocal へ到達可能な強参 照が一つもない場合開放される ● Thread が開放されたら一緒に 開放される
  17. 17. ありがちなリークコード public class ThreadLocalKeyValue { private ThreadLocal tl = new ThreadLocal(); public void add(Object key, Object value) { tl.set(new KeyValuePair(key, value)); } public Object getKey() { return ((KeyValuePair)tl.get()).key; } public Object getValue() { return ((KeyValuePair)tl.get()).value; } private class KeyValuePair { public Object key, value; public KeyValuePair(Object key, Object value) { this.key = key; this.value = value; } } }
  18. 18. テスト ThreadLocalKeyValue target = new ThreadLocalKeyValue(); ReferenceQueue queue = new ReferenceQueue(); PhantomReference ref = new PhantomReference(target, queue); target.add("foo", "bar"); target = null; System.gc(); System.out.println("Released?: " + ref.isEnqueued());
  19. 19. テスト結果 false って何よ ( ゚Д゚)
  20. 20. 修正 public class ThreadLocalKeyValue { private ThreadLocal tl = new ThreadLocal(); public void add(Object key, Object value) { tl.set(new KeyValuePair(key, value)); } public Object getKey() { return ((KeyValuePair)tl.get()).key; } public Object getValue() { return ((KeyValuePair)tl.get()).value; } private static class KeyValuePair { public Object key, value; public KeyValuePair(Object key, Object value) { this.key = key; this.value = value; } } }
  21. 21. テスト結果 true
  22. 22. ハァ ? ( ゚Д゚)
  23. 23. ThreadLocal まとめ ● 設定した値は Thread から強参照される ● ThreadLocal に渡す「値」の参照関係に注意 ● スレッドのコントロールが自分に無い環境では Thread の開放に伴う ThreadLocal の開放は 期待できない – アプリケーションサーバ上では当然スレッドは プールされている – リークしないのは「入れたら確実に消す ( 一時的な 利用 ) 」か「入れっぱなしでも値の参照関係が安 全だと保証できる」場合のみ
  24. 24. ThreadLocal と Tomcat ● Tomcat はアンデプロイ時に ThreadLocal を リフレクションで開放してくれる機能がある – アプリケーションやフレームワーク、ライブラリ のクラスローダリークバグを隠してしまういやん な機能 – 心当たりのあるフレームワーク / ライブラリ開発者 さんは直してください! ● でもその機能にスレッドセーフじゃないバグが あるので 6.0.27 以降は無効になっている – https://issues.apache.org/bugzilla/show_bug. cgi?id=48895
  25. 25. パターン その2 java.util. logging
  26. 26. java.util.logging の Level ● Level 継承するとクラスローダ がリークする ● ここ嫁 ● http://blogs.sun.com/fkieviet/entry/cl assloader_leaks_the_dreaded_java
  27. 27. パターン その 3 既成 ライブラリ
  28. 28. 既成ライブラリ ● 元々複数のクラスローダ上で動作することを想 定していないライブラリ – ContextClassLoader や static フィールドの誤用 – ThreadLocal や WeakHashMap などの参照構造 の理解不足
  29. 29. 既成ライブラリ ● Commons-logging – だいぶ前に一通り直ったけど、利用する側のコー ドによってはリークする ● Commons-beanutils – 1.8.0 時点で一応メジャーな問題は全部解決してい る – https://issues.apache.org/jira/browse/BEANU TILS-291 ● 他にもいっぱいあるよ!

×