Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

JVMのGCアルゴリズムとチューニング

16,871 views

Published on

社内勉強会で、JVMのGCについて調べて話した時の資料を最低限の修正を加えて公開してます。寺田さん監訳の『Javaパフォーマンス』をベースにいろいろ調べてまとめました。

Published in: Technology
  • Login to see the comments

JVMのGCアルゴリズムとチューニング

  1. 1. JVMのGCアルゴリズム とチューニング
  2. 2. このスライド • 社内勉強会で用いたスライドです。 • アニメーションを取り除くなどの最低限の修正を 加えて公開してます。
  3. 3. 対象Java • Java6,7,8ぐらいでの話
  4. 4. 対象聴講者 • Javaのオブジェクトがインスタンス化される際、ヒー プに割り当てられてられることを知っている。 • GCがいらなくなったインスタンスをヒープから削除 してることを知っている。 (が、実際どんな風にしているかしらない) ぐらいの知識レベルの人
  5. 5. スライドのゴール • JVMの主なGCの種類とそれぞれのアルゴリズ ムをなんとなく把握することができた。 • GC選択の際の大まかな指針を知ることができ た。 • それぞれのGCをチューニングの基礎ふんわり 理解した。
  6. 6. 目次 • 自己紹介 • Garbage Collectionとは • 世代で分けられたヒープ • GCアルゴリズム • GCアルゴリズムの大まかな選び方 • GCアルゴリズムのチューニング基礎
  7. 7. 自己紹介 名前:ヒロオカ Twitter: @all_became_f 仕事:都内のSIerで働いている。 趣味:漫画、酒(芋焼酎、ビール)、カメラ
  8. 8. Garbage Collectionとは
  9. 9. • どこからも参照されてないインスタンスを削除し、 ヒープを開放する。 • 解放されたヒープの領域は再利用可能になる。 Garbage Collectionとは
  10. 10. 世代で分けられたヒープ
  11. 11. ヒープをそのまま使った場合 ヒープをそのまま使うと… ⇒毎回ヒープ全領域に対してGCを行う必要があり 非効率
  12. 12. ヒープを世代別に分けて管理 JVMでは多くのインスタンスはすぐに参照が切れる という性質を用いて世代別にヒープを管理している。 世代別に管理をする。 ⇒必要な範囲に必要な頻度でGCを行うため効率的 Eden Survivor(0,1) Old Young
  13. 13. それぞれの領域 Survivor(0,1)領域 Eden領域にGCが走った際、参照が切れてないインスタンス割り当てられる領域 Old領域 Survivor or Eden 領域から、参照が切れなかったインスタンス割り当てられるメモ リ領域。 Eden領域 オブジェクトがインスタンス化される際に一番最初に割り当てられる領域 Eden Survivor(0,1) Old Young領域 Young
  14. 14. 領域別のGC • マイナーGC Young領域に対するGC アプリケーションプロセスを停止 時間はかからない。 • フルGC Young領域, Old領域に対するGC アプリケーションプロセスを停止 時間がかかる。
  15. 15. Stop The World(STW) • アプリケーションプロセスが停止すること • アプリケーションの性能が落ちる
  16. 16. GCアルゴリズム
  17. 17. GCのアルゴリズム 複数ある シリアルGC パラレルGC CMS G1 経緯 • メモリやCPUの低価格化などによるサーバの高 性能化に合わせて、GCが追加されてきた。
  18. 18. 大きく2種に分けられるGCアルゴリズム GCの際に… アプリケーションが完全停止 • シリアル型 • マルチスレッド(スループット)型 部分的にアプリケーションと並行で、コンカレントに処理 • コンカレント型 ・ CMS ・ G1
  19. 19. Java6までのGC • シリアル型 • マルチスレッド(スループット)型 • CMS(コンカレント型)
  20. 20. Java6までのGC • シリアル型 • マルチスレッド(スループット)型 • CMS(コンカレント型) まずはこの3つを見ていく
  21. 21. マイナーGC Eden Survivor Old • シリアル型でも、パラレル型でもコンカレント型で もアルゴリズムは同じ Young ここをGC
  22. 22. f o o f o o f o o f o o h o g e h o g e h o g e マイナーGC発生条件 Stirng hoge = new String(); Eden Survivor Old Stirng hogehoge = new String(); インスタンスは最初にEden領域に割り当てられる Stirng foofoo = new String(); Stirng foo = new String();
  23. 23. p i n g f o o f o o f o o f o o h o g e h o g e h o g e マイナーGC発生条件 Stirng hoge = new String(); Eden Survivor Old Stirng hogehoge = new String(); Eden領域がいっぱいになるとマイナーGCが発生する Stirng foofoo = new String(); Stirng foo = new String(); Stirng ping= new String(); マイナー GC発生
  24. 24. p i n g f o o f o o f o o f o o h o g e h o g e h o g e Edenに対する処理 Stirng hoge = new String(); Eden Survivor Old Stirng hogehoge = new String(); 参照されていないオブジェクトの領域を解放 Stirng foofoo = new String(); Stirng foo = new String(); Stirng ping= new String(); すでに使われていない オブジェクト
  25. 25. p i n g Edenに対する処理 Eden Survivor Old 参照されていないオブジェクトの領域を解放 Stirng ping= new String();
  26. 26. 残ったオブジェクトをSurvivor領域へ移動 p i n g Edenに対する処理 Eden Survivor Old Stirng ping= new String();
  27. 27. 残ったオブジェクトをSurvivor領域へ移動 p i n g Edenに対する処理 Eden Survivor Old Stirng ping= new String();
  28. 28. p i n g p i n g p o n g f o o f o o f o o h o g e h o g e h o g e Survivorに対する処理 Stirng hoge = new String(); Eden Survivor Old Stirng hogehoge = new String(); Young領域へのGCと同じタイミングで発生 Stirng foofoo = new String(); Stirng foo = new String(); Stirng ping = new String(); マイナー GC発生Stirng pingpong = new String();
  29. 29. p i n g p i n g p o n g f o o f o o f o o h o g e h o g e h o g e Survivorに対する処理 Stirng hoge = new String(); Eden Survivor Old Stirng hogehoge = new String(); Young領域へのGCと同じタイミングで発生 Stirng foofoo = new String(); Stirng foo = new String(); Stirng ping = new String(); Stirng pingpong = new String(); ※Edenだけではなく、 Survivorでも使われていな いものは解放される
  30. 30. p i n g p i n g p o n g Survivorに対する処理 Eden Survivor Old Young領域へのGCと同じタイミングで発生 Stirng ping = new String(); Stirng pingpong = new String(); ※Edenだけではなく、 Survivorでも使われていな いものは解放される
  31. 31. p i n g p i n g p o n g Survivorに対する処理 Eden Survivor Old Stirng ping = new String(); Stirng pingpong = new String(); EdenとSurvivorで参照の切れていないものをもう一つのSurvivorへ
  32. 32. p i n g p i n g p o n g Survivorに対する処理 Eden Survivor Old Stirng ping = new String(); EdenとSurvivorで参照の切れていないものをもう一つのSurvivorへ Stirng pingpong = new String();
  33. 33. Old領域への移動(昇格)条件 • 複数回(デフォルト7回)Survivor領域に残り 続けた高年齢のインスタンス • Young領域がいっぱいになった際、Survivor 領域かEden領域で参照が切れていないイ ンスタンス
  34. 34. フルGC • シリアル型、パラレル型はYoung領域からOld領 域への昇格に失敗した場合発生 • CMSではコンカレントサイクル(後述)に失敗した 場合発生 Eden Survivor Old Young 全体をGC
  35. 35. シリアル型のフルGC Eden Survivor Old
  36. 36. シリアル型のフルGC Eden Survivor Old 1. Old領域移動する昇格に失敗する。 Oldがいっぱいで 昇格できない
  37. 37. シリアル型のフルGC 2. アプリケーションプロセスを停止する。 Eden Survivor Old 1. Old領域移動する昇格に失敗する。 Oldがいっぱいで 昇格できない
  38. 38. シリアル型のフルGC 2. アプリケーション(AP)プロセスを停止する。 Eden Survivor Old 3. 参照されていないオブジェクトの解放 1. Old領域移動する昇格に失敗する。
  39. 39. シリアル型のフルGC 2. アプリケーション(AP)プロセスを停止する。 Eden Survivor Old 3. 参照されていないオブジェクトの解放 1. Old領域移動する昇格に失敗する。 4. コンパクト化する。 コンパクト化
  40. 40. シリアル型のフルGC 2. アプリケーション(AP)プロセスを停止する。 Eden Survivor Old 3. 参照されていないオブジェクトの解放 1. Old領域移動する昇格に失敗する。 4. コンパクト化する。
  41. 41. パラレル型のフルGC 2. アプリケーションプロセスを停止する。 3. 参照されていないオブジェクトの解放 4. コンパクト化する。 1. Old領域への昇格が失敗する。 Eden Survivor Old ここまではシリアル型と同じ
  42. 42. パラレル型のフルGC 2. アプリケーションプロセスを停止する。 3. 参照されていないオブジェクトの解放 4. コンパクト化する。 ここの手順を 複数スレッドで 1. Old領域への昇格が失敗する。 Eden Survivor Old
  43. 43. CMSのコンカレントサイクルとフルGC Eden Survivor Old
  44. 44. CMSのコンカレントサイクルとフルGC Eden Survivor Old 1.マイナーGCが走り、 Old領域の使用率が閾値 (デフォルトで7割)を超える。
  45. 45. CMSのコンカレントサイクルとフルGC Eden Survivor Old 2. APプロセスを止めずに参照されていない インスタンスを解放する。 1.マイナーGCが走り、 Old領域の使用率が閾値 (デフォルトで7割)を超える。
  46. 46. CMSのコンカレントサイクルとフルGC Eden Survivor Old 2. APプロセスを止めずに参照されていない インスタンスを解放する。 1.マイナーGCが走り、 Old領域の使用率が閾値 (デフォルトで7割)を超える。 3. 1. 2.のプロセスが繰り返される。(コンカレントサイクル)
  47. 47. CMSのコンカレントサイクルとフルGC Eden Survivor Old 2. APプロセスを止めずに参照されていない インスタンスを解放する。 1.マイナーGCが走り、 Old領域の使用率が閾値 (デフォルトで7割)を超える。 3. 1. 2.のプロセスが繰り返される。(コンカレントサイクル) 4. 解放が間に合わなかった場合 にフルGC(APプロセス を止めて、解放&コンパクト化)
  48. 48. CMSのコンカレントサイクルとフルGC Eden Survivor Old 2. APプロセスを止めずに参照されていない インスタンスを解放する。 1.マイナーGCが走り、 Old領域の使用率が閾値 (デフォルトで7割)を超える。 3. 1. 2.のプロセスが繰り返される。(コンカレントサイクル) 4. 解放が間に合わなかった場合 にフルGC(APプロセス を止めて、解放&コンパクト化) コンカレントモードが失敗 Concurrent Mode Failure
  49. 49. Java6までのGCの問題点 • メモリが大きくなれば処理に時間がか かり、結局遅くなる。 解決策 Garbage First(G1)
  50. 50. O OS S S S E O Garbage First(G1)GC • Java7で追加 • ヒープを細かくわけた(デフォルトで2,048個)リー ジョンと呼ばれる単位で管理 • 世代領域をそれぞれのリージョンに分散して配置 S S O E E S OE Eden Survivor Old
  51. 51. G1GCの大まかな処理の流れ 1. マイナーGCを行なう。 2. ヒープの使用率が高くなると、ゴミが多いOld 領域のリージョンにマーキングを開始 3. 十分にマーキングができるとサイクルを停止 4. ゴミが多い領域を集中してGC(混合GC)
  52. 52. G1GCの大まかな処理の流れ 1. マイナーGCを行なう。 2. ヒープの使用率が高くなると、ゴミが多いOld 領域のリージョンにマーキングを開始 3. 十分にマーキングができるとサイクルを停止 4. ゴミが多い領域を集中してGC(混合GC) これゆえに、Garbage Firstと呼ばれる。
  53. 53. G1GCの大まかな処理の流れ 1. マイナーGCを行なう。 2. ヒープの使用率が高くなると、ゴミが多いOld 領域のリージョンにマーキングを開始 3. 十分にマーキングができるとサイクルを停止 4. ゴミが多い領域を集中してGC(混合GC)
  54. 54. SS S S E マイナーGC S S S OO O E E E 1.Eden領域を昇格&Survivor領域を再配置
  55. 55. SS S S S ES S マイナーGC S S S OO O E E E New New New 1.Eden領域を昇格&Survivor領域を再配置
  56. 56. S S S S ES S マイナーGC OO O New New New 1.Eden領域を昇格&Survivor領域を再配置
  57. 57. S S S S ES S マイナーGC OO O New New New 1.Eden領域を昇格&Survivor領域を再配置 高年齢な インスタンス Survivor領域に入りきら なかったオブジェクト 2.『高年齢である』 or 『Suvivor領域に入りきら なかった』インスタンスを昇格させる。
  58. 58. OS S S S E O S S マイナーGC OO O New New New 1.Eden領域を昇格&Survivor領域を再配置 高年齢な インスタンス Survivor領域に入りきら なかったオブジェクト 2.『高年齢である』 or 『Suvivor領域に入りきら なかった』インスタンスを昇格させる。
  59. 59. O S O S S マイナーGC OO O New New New 1.Eden領域を昇格&Survivor領域を再配置 2.『高年齢である』 or 『Suvivor領域に入りきら なかった』インスタンスを昇格させる。
  60. 60. G1GCの大まかな処理の流れ。 1. マイナーGCを行なう。 2. ヒープの使用率が高くなると、ゴミが多いOld 領域のリージョンにマーキングを開始 3. 十分にマーキングができるとサイクルを停止 4. ゴミが多い領域を集中してGC(混合GC)
  61. 61. G1GCの大まかな処理の流れ。 1. マイナーGCを行なう。 2. ヒープの使用率が高くなると、ゴミが多いOld 領域のリージョンにマーキングを開始 3. 十分にマーキングができるとサイクルを停止 4. ゴミが多い領域を集中してGC(混合GC) このマーキングサイクルを コンカレントに行なう。
  62. 62. O O S E O S S マーキングサイクル SO O E E 1. マイナーGCの後、ヒープの使用率が閾値(デフォルト 45%)以上でマーキングサイクルが発生
  63. 63. O O S E O S S マーキングサイクル SO O E E 1. マイナーGCの後、ヒープの使用率が閾値(デフォルト 45%)以上でマーキングサイクルが発生 2. ほとんど不使用と判断されたOld領域をマーキング (黒色の領域)
  64. 64. O O S E O S S マーキングサイクル SO O E E 1. マイナーGCの後、ヒープの使用率が閾値(デフォルト 45%)以上でマーキングサイクルが発生 3. 解放可能な領域がヒープ全体の閾値(デフォルトで 5%)以上になればマーキングサイクルを停止 2. ほとんど不使用と判断されたOld領域をマーキング (黒色の領域)
  65. 65. G1GCの大まかな処理の流れ。 1. マイナーGCを行なう。 2. ヒープの使用率が高くなると、ゴミが多いOld 領域のリージョンにマーキングを開始 3. 十分にマーキングができるとサイクルを停止 4. ゴミが多い領域を集中してGC(混合GC)
  66. 66. S S O O O O S E O S S 混合GC SO O E E New New New New マーキングサイクルでマーキングした Old領域とYoung領域をGCする。
  67. 67. S S O O O O 混合GC O New New New New マーキングサイクルでマーキングした Old領域とYoung領域をGCする。 マイナーGCも一緒に起きるので、混合 GCと呼ばれる。
  68. 68. G1のフルGCの原因 主な原因 • 移動の失敗 • Concurrent Mode Failure • 昇格の失敗
  69. 69. 移動の失敗 1. マイナーGCを行なう。 2. ヒープの使用率が高くなると、ゴミが多いOld 領域のリージョンにマーキングを開始 3. 十分にマーキングができるとサイクルを停止 4. ゴミが多い領域を集中してGC(混合GC) Suviver領域がいっぱいで移動が行えなかった場 合。フルGCが発生する可能性がある。
  70. 70. Concurrent Mode Failure 1. マイナーGCを行なう。 2. ヒープの使用率が高くなると、ゴミが多いOld 領域のリージョンにマーキングを開始 3. 十分にマーキングができるとサイクルを停止 4. ゴミが多い領域を集中してGC(混合GC) この際にOld領域がいっぱいになってしまう
  71. 71. 昇格の失敗 1. マイナーGCを行なう。 2. ヒープの使用率が高くなると、ゴミが多いOld 領域のリージョンにマーキングを開始 3. 十分にマーキングができるとサイクルを停止 4. ゴミが多い領域を集中してGC(混合GC) この際にOld領域がいっぱいになってしまう
  72. 72. GCアルゴリズム の選び方
  73. 73. デフォルトGC ・ Windows 32bit - シリアル 64bit パラレル Linux 32bit 1CPUまたは2GBメモリ未満 シリアル 2CPU以上かつ2GBメモリ以上 パラレル 64bit パラレル • Java8まではシリアル型orパラレル型がデフォルト • Java9以降ではG1がデフォルト
  74. 74. デフォルトのままだと… PCのスペックにあったベストなGCであるとは限 らない。
  75. 75. 『大まかにGC選択する時』のフロー図 開始 シリアル G1 CMSパラレル メモリが100MB以下 Or 単一コア メモリが4GB以上か? CPUの使用率が高い状態か? Yes No No No Yes Yes
  76. 76. 『大まかにGC選択する時』のフロー図 開始 シリアル G1 CMSパラレル メモリが100MB以下 Or 単一CPU メモリが4GB以上か? CPUの使用率が高い状態か? Yes No No No Yes Yes 詳細な条件を考えず、単一アプリケーションの 単位時間当たりの平均処理量を比較した時
  77. 77. 『大まかにGC選択する時』のフロー図 開始 シリアル G1 CMSパラレル メモリが100MB以下 Or 単一コア メモリが4GB以上か? CPUの使用率が高い状態か? Yes No No No Yes Yes 100MB以下では他では効果が薄い 単一コアのCPUだと複数スレッド持てない
  78. 78. 『大まかにGC選択する時』のフロー図 開始 シリアル G1 CMSパラレル メモリが100MB以下 Or 単一コア メモリが4GB以上か? CPUの使用率が高い状態か? Yes No No No Yes Yes G1では4G以上のメモリで最大限の性能 が発揮されるように設計されている
  79. 79. 『大まかにGC選択する時』のフロー図 開始 シリアル G1 CMSパラレル メモリが100MB以下 Or 単一コア メモリが4GB以上か? CPUの使用率が高い状態か? Yes No No No Yes Yes CPUの使用率が高い場合はCMSの性能が 劣る。
  80. 80. あくまで大まかな指針 • 実際は、アプリケーション特性等を考える。 –アプリケーションは停止してもよいか –全体としての処理の速さが求められるのか …などを考えてGCを選択する
  81. 81. GCアルゴリズムの チューニング基礎
  82. 82. チューニングの必要性 • GCチューニングをしないと…. ⇒GCがアプリケーションの性能を下げてしまうこ ともある。
  83. 83. チューニングの基本的な指針 ゴール • 長いSTWが発生する、フルGCの回数をちょうどい い感じに減らす アプローチ
  84. 84. チューニングの基本的な指針 ゴール • 長いSTWが発生する、フルGCの回数をちょうどい い感じに減らす アプローチ ※何も考えずに単に減らすと、 逆に性能が悪くなったりする。
  85. 85. チューニングの基本的な指針 ゴール • 長いSTWが発生する、フルGCの回数をちょうどい い感じに減らす アプローチ それぞれのGCによって違う。 ※何も考えずに単に減らすと、 逆に性能が悪くなったりする。
  86. 86. パラレル(シリアル)型のチューニング アプローチ • Old領域を調整する。 ・ ヒープサイズの拡大 ・ Young領域、Old領域の調整 トレードオフ ・ ヒープサイズを大きくすると… フルGCの頻度 一回のフルGCの停止時間 ・ Young領域を大きくすると… フルGCの頻度 一回のフルGCの停止時間
  87. 87. パラレル(シリアル)型のチューニング アプローチ • Old領域を大きくする。 ・ ヒープサイズの拡大 ・ Young領域、Old領域の調整 トレードオフ ・ ヒープサイズを大きくすると… フルGCの頻度 一回のフルGCの停止時間 ・ Young領域を大きくすると… フルGCの頻度 一回のフルGCの停止時間 これらを考慮して 調整していくのは大変
  88. 88. パラレル(シリアル)型のチューニング アプローチ • Old領域を大きくする。 ・ ヒープサイズの拡大 ・ Young領域、Old領域の調整 トレードオフ ・ ヒープサイズを大きくすると… フルGCの頻度 フルGCの所要時間 ・ Young領域を大きくすると… フルGCの頻度 フルGCの所要時間 Adaptive Sizingが うまいことやってくれる。 お任せください JVM
  89. 89. Adaptive Sizing • パラレルGCのパラメータを自動で調整してくれる。 以下の2つのどちらかを設定してすると、ベストエ フォート型で調整 MaxGCPauseMillis STWの最長時間。ミリ秒で指定 GCTimeRatio APプロセスがGCに対して何%をしめるか
  90. 90. Adaptive Sizing • パラレルGCのパラメータを自動で調整してくれる。 以下の2つのどちらかを設定してすると、ベストエ フォート型で調整 MaxGCPauseMillis STWの最長時間。ミリ秒で指定 GCTimeRatio APプロセスがGCに対して何%をしめるか • 性能目標に合わせて値を設定 • 『MaxGCPauseMillis』が優先
  91. 91. CMSのチューニング • Old領域の拡大 ・ ヒープ領域の拡大が効果的 ・ Adaptive Sizingあり • バックグラウンドのスレッド数 ⇒CPUに余裕があれば増やす方がよい。 • コンカレントサイクルが起こる頻度の設定 ⇒常にコンカレントサイクルを起こしていてもよいがこのサイ クルには部分的に停止(STW)するため調整が必要
  92. 92. G1のチューニング • Old領域を大きくする ⇒トレードオフ • バックグラウンドのスレッド数を増やす ⇒CPUに余裕があれば… • バックグラウンドの処理頻度を増やす ⇒CPUの(ry • 一回の混合GCで行なわれる量を増やす。 ⇒むつかしい….
  93. 93. G1のチューニング • Old領域を大きくする ⇒トレードオフ • バックグラウンドのスレッド数を増やす ⇒CPUに余裕があれば… • バックグラウンドの処理頻度を増やす ⇒CPUの(ry • 一回の混合GCで行なわれる量を増やす。 ⇒むつかしい…. 考えなければいけない ことが多すぎる…
  94. 94. G1のチューニング • Old領域を大きくする ⇒トレードオフ • バックグラウンドのスレッド数を増やす ⇒CPUに余裕があれば… • バックグラウンドの処理頻度を増やす ⇒CPUの(ry • 一回の混合GCで行なわれる量を増やす。 ⇒むつかしい…. • G1GCの目的の1つに『多くのチューニングを求 めない』がある。 • MaxGPauseMillsフラグがG1でも用意されている。 まずはMaxGPauseMillsの設定を考える。 JVM 働きます!
  95. 95. まとめ • GCの種類について ⇒ シリアル型、パラレル型、CMS、G1 • GCの選び方 ⇒ヒープに割り当てることができるメモリの大きさ、 コア数をなど考慮して選択 • チューニング ⇒ MaxGPauseMillsなどの自動調整の仕組みに任 せて、細かいところはひとまずJVMに任せる。
  96. 96. Thank you for your attention

×