Javaはどのように動くのか~スライドでわかるJVMの仕組み

28,665 views
29,887 views

Published on

日本Javaユーザーグループ
JJUG ナイトセミナー 2 月 27 日(水)
http://www.java-users.jp/?p=309
注:サンプルソースはあくまでも例であり、その修正例も完全なものではありません。

Published in: Technology
1 Comment
82 Likes
Statistics
Notes
No Downloads
Views
Total views
28,665
On SlideShare
0
From Embeds
0
Number of Embeds
7,312
Actions
Shares
0
Downloads
185
Comments
1
Likes
82
Embeds 0
No embeds

No notes for slide

Javaはどのように動くのか~スライドでわかるJVMの仕組み

  1. 1. Javaはどのように動くのか~スライドでわかるJVMの仕組み 伊藤 智博 1
  2. 2. ここで示されている見解は私個人のものであり、所属会社の見解を反映したものではありません 2
  3. 3. 目次 • 自己紹介 • はじめに • ヒープ • スレッド • メモリリーク • ファイナライザ3
  4. 4. 自己紹介• 名前: – 伊藤 智博(いとう ちひろ)• 勤務先: – 日本オラクル株式会社• 仕事で使う製品: – Coherence, Java EE/SE/ME, JVM, Database• 連載: – Javaはどのように動くのか~図解でわかるJVMの仕組み – http://gihyo.jp/dev/serial/01/jvm-arc 4
  5. 5. はじめに5
  6. 6. JVMって何なの?• Java仮想マシン(JVM) – Javaバイトコードを実行するスタック型の仮想マシン – APIやツールのセットでJava実行環境(JRE) – この環境を移植することで、様々な環境でJavaを実行できる• JDK(Java開発キット) – プライベートJREや開発ツールで構成されている – サンプルソースが含まれている wikipediaより抜粋 JDK JRE 開発 実行 ツール 環境 6
  7. 7. JVMにはどんなのがあるの?• Hotspot – 旧Sunが開発を行っていたJVM – 一般的にJVMと言ったらこれ。• JRockit – 旧BEAが開発を行っていたJVM – サーバ用にいろいろされている。• ほかにもいろいろな会社さんがリリースしてます 7
  8. 8. 開発から実行まで • 開発者がソースコードを書く • javacでコンパイルして、クラスファイルを生成 • クラスファイルをロードする • ネイティブコードを生成&実行 java クラス ネイティブ ソース コンパイル コード コード ファイル ロード javac 変換 JVM コーディング 実行開発者 8
  9. 9. 主なメモリ空間• スレッドスタック JVM – スレッドの情報が入る メモリ空間• Cヒープ スレッド Cヒープ Java スタック ヒープ – JVMがいろいろ使う• Javaヒープ – アプリがいろいろ使う Java JVMと選択したGCに ヒープ よって形が変わる 若い世代 古い世代 古い世代 9
  10. 10. 連載ではこんなふうに例えています• OSのメモリ空間は『地面』• OSからJVMに割り当てられるメモリ空間が『敷地』• Javaヒープが『建物』• Javaヒープ以外のメモリ空間が『庭』 Javaヒープ Javaヒープ以外 庭 建物JVMのメモリ空間 OSのメモリ空間 JVM メモリ空間 スレッド Java Cヒープ 10 スタック ヒープ
  11. 11. 実際の大きさを測るには • 敷地のサイズは今や無限のようなもの • 処理によっては庭がガンガン大きくなっていくことも • 建物は固定サイズおすすめ 建物サイズ(抜粋)庭サイズ jstat -gccapacity 5908 庭=敷地-建物 NGC OGC PGC 43072.0 86144.0 21248.0 庭 建物 敷地サイズ(抜粋) ps u –P 5908 VSZ 116472 11
  12. 12. ヒープ12
  13. 13. 巨大オブジェクトのサンプルソース• 25,000,000個のint配列を作成し、最後にHelloを出力します – (4byte*25M個の配列=約100Mbyte) Create100mObject.java public class Create100mObject { public static void main(String[] args) { int[] a = new int[25000000]; System.out.println("Hello."); } } 13
  14. 14. オブジェクトを作成してみよう(1)• 実行してみると、• 約100Mbyteの配列が作成され、Helloが出力されました。>java Create100mObjectHello. new アプリの処理スレッドはnew によって建物にオブジェクト 庭 建物 を生成します。 14
  15. 15. オブジェクトを作成してみよう(2) • ヒープのサイズを64MBにして実行してみます。>java Create100mObject -Xmx64m –Xms64mException in thread "main" java.lang.OutOfMemoryError: Java heap spaceat Create100mObject.main(Create100mObject.java:3)エラー発生!! new 建物に入りきらないオブジェクト 建物 は格納できず、OOMEが発生し ます。 15
  16. 16. スレッド16
  17. 17. スレッド• JVMはメモリの他にスレッドというものも持っています• スレッドには処理が定義されていてそれを実行します。私はアプリを動 僕はGCしますかします 庭 建物 敷地には何人かの人が居ます。 この人達は、それぞれ何かし らの役割を持っています。 17
  18. 18. スレッドダンプ• Jstackによるスレッドダンプを取得>jstack 101042013-02-22 18:13:51Full thread dump Java HotSpot(TM) 64-Bit Server VM (23.7-b01 mixed mode):"Service Thread" daemon prio=6 tid=0x000000000bb4f800 nid=0x2aa4 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE"C2 CompilerThread1" daemon prio=10 tid=0x000000000bb4a800 nid=0x208c waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE"C2 CompilerThread0" daemon prio=10 tid=0x000000000bb36800 nid=0x1e3c waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE"Attach Listener" daemon prio=10 tid=0x000000000bb36000 nid=0xe58 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE"Signal Dispatcher" daemon prio=10 tid=0x000000000bb2f000 nid=0x2210 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE"Finalizer" daemon prio=8 tid=0x00000000024ac800 nid=0x1fbc in Object.wait() [0x000000000ccce000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000007d5eb5798> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135) - locked <0x00000007d5eb5798> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177)"Reference Handler" daemon prio=10 tid=0x00000000024a4800 nid=0x1f90 in Object.wait() [0x000000000cddf000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000007d5eb5320> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:503) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133) - locked <0x00000007d5eb5320> (a java.lang.ref.Reference$Lock)"main" prio=6 tid=0x000000000256e000 nid=0x2888 waiting on condition [0x00000000028df000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at ThreadSleep.main(ThreadSleep.java:9)"VM Thread" prio=10 tid=0x000000000ba92000 nid=0x1e98 runnable"GC task thread#0 (ParallelGC)" prio=6 tid=0x00000000023f4000 nid=0x2a6c runnable"GC task thread#1 (ParallelGC)" prio=6 tid=0x00000000023f5800 nid=0x2204 runnable"VM Periodic Task Thread" prio=10 tid=0x000000000bb60800 nid=0x2738 waiting on conditionJNI global references: 110 18
  19. 19. スレッドダンプ(抜粋) • コンパイラスレッドが2つ "C2 CompilerThreadn” • ファイナライザスレッドが1つ ”Finalizer” • アプリを実行するスレッドが1つ ”main” • GCスレッドが2つ ”GC task thread#n (ParallelGC)” >jstack 10104 "C2 CompilerThread1” java.lang.Thread.State: RUNNABLEコンパイラ "C2 CompilerThread0” java.lang.Thread.State: RUNNABLEファイナライザ "Finalizer” java.lang.Thread.State: WAITING (on object monitor)アプリ "main” java.lang.Thread.State: TIMED_WAITING (sleeping) "GC task thread#0 (ParallelGC)“ runnableGC "GC task thread#1 (ParallelGC)“ runnable 19
  20. 20. メモリリーク20
  21. 21. メモリリークとは?• オブジェクトが必要無いのに参照されてしまい、 GCされても削除されずに残ってしまうこと。 不要になったオブジェクト 参照されてるからあ 参照 GC のオブジェクトは消必要無いのに参照が残ってしまい、オブジェク 建物 せないなぁトがGC対象にならない 21
  22. 22. メモリリークはダメなのか?• メモリリークが起きるとどうなるのか? – ヒープを圧迫する – プログラムが想定外の動きをすることも(=バグ)使える領域が狭い アプリが使える領域気がするけど、なぜ? 不要なのに参照が 残っているオブジェ 建物 クトがヒープを圧迫頻繁に働いてる気がする・・・ 不要なオブジェクト GC 22
  23. 23. インターフェース Map<K,V>• V put(K key, V value) – 概要 • 指定された値と指定されたキーをこのマップに関連付けます (任意のオペレーション)。マップにすでにこのキーに対する マッピングがある場合、古い値は指定された値に置き換えられ ます。m.containsKey(k) が true を返す場合に限り、マッ プ m は、キー k のマッピングを含むと言えます。 – パラメータ: • key : 指定された値が関連付けられるキー • value : 指定されたキーに関連付けられる値 – 戻り値: • key に以前に関連付けられていた値。key のマッピングが存在 しなかった場合は null。Java 7では日本語が無かったので6から抜粋 23http://docs.oracle.com/javase/jp/6/api/java/util/Map.html#put(K, V)
  24. 24. Map put(K,V)のイメージ HashMapオブジェクトput( key, value ) valueの値を格納 keyの値によって 格納場所が決まる 24
  25. 25. メモリリークのサンプルソース(1)• Mapのキーとなるクラス• フィールド i が同じオブジェクトは同じキーとしたい MemLeak.java public class MemLeak { int i; public MemLeak(int i){ this.i = i; } } 25
  26. 26. メモリリークのサンプルソース(2)• 部分でputしたオブジェクトを 部分でどんどん上書き• 最後にMapクラスの c に入っているデータの数を出力 MemLeak.java(メイン処理部分) public static void main(String[] args) { Map<MemLeak,Object> c = new HashMap(); c.put(new MemLeak( 1 ),new Object()); for(int i = 0 ; i < 100; i++){ c.put(new MemLeak( 1 ),new Object()); } System.out.println(c.size()); } 26
  27. 27. 問題• このmainメソッドを実行すると何が出力されるでしょ うか?• A. 1が出力される• B. 100が出力される• C. 101が出力される• D. 実行時エラーになる• E. その他 27
  28. 28. メモリリークを起こしてみよう>java MemLeak101• 正解は、Cの101• 今回の問題は、同値の判定を行っていないため。• hashCode()とequals(Object)を修正します 28
  29. 29. メモリリークの修正例 MemLeak.java(一部抜粋) @Override public int hashCode(){ return this.i; } @Override public boolean equals(Object o){ MemLeak a = (MemLeak)o; return (this.i == a.i); }>java MemLeak1 29
  30. 30. ファイナライザ30
  31. 31. ファイナライザとは?• 全参照が削除されたオブジェクトは次回のGCで削除• GCの前にfinalize()が実行されます。 – 基本的にfinalize()は何も処理は行われません• finalize()が実行されたオブジェクトはGCで回収 ② ファイナライザ もう要らないので finalize()メソッドを ① finalize() 実行します 参照を削除 ③ 建物 finalize()された ので回収します 31
  32. 32. ファイナライザのサンプルソース(1)• finalize()の中で処理を1秒間止めます Fin.java public class Fin{ public void finalize() { try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } 32 }
  33. 33. ファイナライザのサンプルソース(2)• Finクラスのオブジェクトを大量に生成します Fin.java(メイン処理部分) public static void main(String[] args) { for (;;) { new Fin(); } } 33
  34. 34. 実行してみよう• Finオブジェクトを大量に生成• FinオブジェクトはGC前にfinalize()でスレッドが1秒間停止• すると・・・ 34
  35. 35. ファイナライザが終わらないとこうなる>java Fin -Xmx64m –Xms64mException: java.lang.OutOfMemoryError thrown from theUncaughtExceptionHandler in thread "main"ヒープに空きが無い 不要なオブジェクトからオブジェクトが ファイナライザが終作れない・・・ わらないから回収 できないなぁ finalize()が終わ らない・・・ 建物 35
  36. 36. まとめ• 動きを知ると問題が起きても解決が早くなります• 特定のJVM固有の知識も必要だが、 種類に問われない汎用的な知識も必要 36

×