Comments
Description
Transcript
JVM設計 1 WASV7.0によるWebシステム基盤設計Workshop
WASV7.0によるWebシステム基盤設計Workshop JVM設計 1 当セッションの目的 JVM設計に必要な知識の習得 JVM設計に影響するGCを理解する。 WAS32bit版とWAS64bit版の違いを理解する。 その他、WAS V7.0のパフォーマンス向上機能を理解する。 2 2 Agenda 1. はじめに 2. GCの基本 3. GCポリシー 4. GCチューニング 5. WAS V7.0 64bit版 6.パフォーマンスの最適化 まとめ・参考文献 3 3 1.はじめに 4 この章では、プロジェクトのどのフェーズまでにJVMに関係した何の事柄が決まっていればいいかについ てご説明致します。 JVMとはJava仮想マシン(Java Virtual Machine : JVM)のことで、Javaバイトコードをそのプラットフォームの ネイティブコードに変換して実行するソフトウェアです。Java言語で開発されたソフトウェアは、配布時にプ ラットフォームから独立した独自の形式(Javaバイトコード)になっているため、そのままでは実行することが できません。このため、そのプラットフォーム固有の形式(ネイティブコード)に変換するソフトウェアを用意 して、変換しながら実行します。この変換と実行を行うのがJVMです。 4 JVM設計時期 このセッションで扱うJVMに関わる設計の決定フェーズは次 のとおりである。 提案 要件定義 基本設計 詳細設計 導入製品決定 32bit版 /64bit版 ヒープ 見積もり決定 環境構築 テスト ヒープチューニング GC 5 このセッションで扱うJVMに関する設計の決定時期はチャートのとおりです。バージョン、エディション、 32bit版/64bit版などの導入製品の選択は、設計が始まる前までに決定します。その後、環境構築までに だいたいのヒープサイズの見積もりをし、最後にテストフェーズで十分なパフォーマンステストを実施しGC 頻度や長さから最適なヒープサイズを決定します。 5 2. GCの基本 6 この章では、基本的なGCの役割や動きを説明します。 6 Heap JVMが使用するメモリ領域 Java heap ¾ ¾ ¾ JVM初期化時に確保される連続したストレージ領域 クラスやインスタンスのオブジェクトを格納 Garbage Collectionの対象エリア Native heap ¾ JVMの起動および稼動に必要なクラスのオブジェクトを格納 ¾ Garbage Collectionの非対象エリア z JNIネイティブ・コード、JITコンパイル・コードなど Java Heap Native Heap 1JVMプロセスが使用可能なメモリ空間 7 Javaアプリケーションの実行環境であるJVMが使用する仮想ストレージは一般にヒープと呼ばれています。 WebSphere Application Server V7.0(以下、WAS V7.0)の使用しているJVMはIBM Developer Kit For Java 5.0から採用されたJ9 VMと呼ばれるJVMです(以後、特に断りのない限り、JVMとはWASに搭載され ているJava仮想マシンを指し示すものとします)。また、JVMのサブコンポーネントでヒープの状態管理(メモ リ管理)を担当しているのはSTコンポーネントと呼ばれます。 ヒープには、格納するオブジェクトの種類によって2種類のヒープが存在します。ひとつはリクエストを実施 するときにアプリケーションによって生成されるオブジェクトを格納するためのJavaヒープであり、Garbage Collectionによるメモリ管理は通常このJavaヒープの状態を管理します。この領域は最小ヒープサイズ・最 大ヒープサイズ(Xms/Xmx)の範囲で増減されます。Javaヒープには、一時オブジェクト(毎回のGCサイク ルの中で消滅)、キャッシュ・オブジェクト(設定によりサイズが変動)、 プールされたオブジェクト(トラフィッ ク状況やタイムアウトによりサイズが変動)、プロセスの消滅まで存在し続けるオブジェクトなどが格納され ます。 もうひとつはアプリケーションの稼働環境に必要なシステムや共有ライブラリのクラスオブジェクトを格納す るためのNative Heapです。Native Heapは、格納されるオブジェクトの性質上Garbage Collectionの対象 になりません。また、ストレージコンポーネントは必要な分だけ領域を確保するような動きをとるため、Java ヒープのようにサイズの最大値、最小値を設定することはできません。 WASV6.1からはNative heapの初期値が、JVM引数-Xinitshで設定することができなくなっていますので、 ご注意下さい。 PK66599: THE JAVA VIRTUAL MACHINE FOR WEBSPHERE APPLICATION SERVER VERSION 6.1 DOES NOT SUPPORT THE XINITSH ARGUMENT http://www.ibm.com/support/docview.wss?rs=180&uid=swg1PK66599 7 GCとは? 不要メモリー領域の自動解放 メモリー管理をシステムに一任する 使用済みのオブジェクトが占有しているストレージ領域を開放して、 新たな割り当て要求に対応が出来るよう連続領域を準備すること 8 Garbage Collection(通称GC)とはJVMによるメモリ管理機能です。GCによって不要なオブジェクトは削除 され、メモリー領域が解放されます。それにより、新たなオブジェクト割り当て要求処理を行うことが可能に なります。C言語のようにプログラマが明示的にヒープの確保と開放を行うのではなく、それらの作業を JVMに委譲することでより安全なプログラムの作成が行えるようになっています。 8 GCの動き Allocation ヒープ領域の割り当て STEP2 Garbage Collection 発生トリガー ¾ ¾ Expansion/Shrinkage STEP1 Allocation Garbage Collection ヒープ領域へのオブジェクト割り当てが失敗した場合 System.gc()が実行された場合 不要なメモリ領域を開放 STEP3 Expansion/Shrinkage GC後にヒープ領域を拡張/縮小することがある 9 GCは次の3つのフェーズから成り立っています。まず、オブジェクトにヒープ領域を割り当てるAllocation フェーズ、その割り当てに失敗した場合に発生するGCフェーズ、最後にGC実施後、十分な空き領域が 確保できなかった場合にヒープの拡張や、十分すぎるメモリ領域が確保されていた場合はヒープの収縮 が発生します。次ページ以降で詳しく説明します。 9 STEP1: Allocation Allocationとは? オブジェクトに対するヒープ領域の確保 種類 cache allocation ¾ ¾ ¾ ヒープ領域を確保するにはヒープ領域をロックする必要があるが、ヒープロックを している間は1スレッドしかヒープにアクセスできない。 スレッドごとに自由にアクセスできるヒープ領域( Thread Local Heap )を用意し、 全体のヒープをロックすることを避ける 512bytes以下の小さなオブジェクトの割り当てのために使用 z 64bitJVMの場合は、768bytes Heap lock Allocation ¾ ¾ TLHへの割り当てに失敗したときに実行 ヒープをロックするため、パフォーマンスはよくない 10 GCの最初のステップとして、まずAllocationがあります。 Allocationには二種類存在します。ひとつは他のスレッドによる割り当てと競合しないようにヒープにロック をかけて割り当てを行う方法で、もうひとつはヒープにロックをかけることなく割り当てを行う方法です。 ヒープをロックすることなく割り当てる方法をcache allocationと呼びます。実行スレッド毎に予め確保されて いるキャッシュ領域(Thread Local Heapと呼ぶ)を利用してそこにオブジェクトを割り当てます。基本的に 512bytes以下(JVM64bitでは768bytes以下)の大きさの小さなオブジェクトの割り当てのために使用されま すが、その時点で使用しているキャッシュ領域に空きがある場合は512bytesを超えるサイズのオブジェクト の割り当ても行われます。ヒープをロックすることなく割り当てが出来るため、小さなオブジェクトの割り当て が多い場合にパフォーマンスの向上が期待できます。TLHがいっぱいになって割り当てが出来なくなった 場合に備えて、スレッドはTLH用の領域を40kBの大きさを上限としてJavaヒープから別途確保しており、小 さなオブジェクトの割り当て要求が来た際にTLHが一杯だった場合はその新しい領域を使用します。 オブジェクトの割り当ての際に他のスレッドとの競合を避けるためにヒープにロックをかけて割り当てを行う のがHeap lock Allocationです。このAllocationは割り当てるオブジェクトのサイズが512bytesを超える場合 で、かつTLHへの割り当てが出来ないときに発生します。 10 STEP2: Garbage Collection (1/6) GC 不要なメモリ領域を解放 不要なメモリ領域とは? Rootから参照されていないオブジェクトに割り当てられたヒープ領域 root 到達可能オブジェクト root 解放可能オブジェクト ポインター 11 GCの2つ目のステップとして、GCがあります。 ヒープ内のオブジェクト管理方法は、「生きている」オブジェクトがどこにあるのかを管理し、「生きている」オ ブジェクトが参照していないオブジェクトをガーベッジと判断します。ガーベッジと判断されたオブジェクト の領域は不要とされ、メモリー解放されます。このガーベッジとなったオブジェクトとは、アプリケーションか ら参照されなくなったオブジェクトのことです。同じ観点からヒープ内の「生きた」オブジェクトは、スレッドの スタックやstaticなフィールドから直接参照しているオブジェクト(Rootオブジェクトと呼ばれています)、およ びRootオブジェクトやその子オブジェクトなどが参照していてRootオブジェクトから到達可能になっている オブジェクトと定義できます。 よって、不要なメモリ領域とは、Rootから参照されていないガーベッジとなっ たオブジェクトに割り当てられたヒープ領域のことを指します。 11 STEP2: Garbage Collection (2/6) GC形態 Mark&Sweep Copying 12 GC形態にはMark&SweepとCopyingの2種類あります。ここでは、「どのようにヒープを解放するか」の説明 をします。詳しくは次ページ以降で説明します。 12 STEP2: Garbage Collection (3/6) Mark&Sweep Mark Phase ¾ ¾ Root全走査、Rootにマーク Rootから到達可能なオブジェクトすべてにマーク Sweep Phase ¾ ¾ Mark:印付け Sweep:掃除 ヒープ領域全走査 マークのついていないオブジェクトをすべて解放 考慮点 Sweepのため最低一度はオブジェクトを全部確認する必要がある GCの負荷が一点に集中する(停止時間が長い) 13 Mark&Sweepには大きくわけて3つのフェーズが存在します。Markフェーズでは、RootおよびRootから到達 可能なオブジェクトに対してマーキングされます。ここでマークされなかった、つまり到達できないオブジェ クトについてはSweepフェーズでヒープ上から削除され、不要メモリが解放されます。 Mark&SweepはGCをMark-Sweep-Compactionの三つのフェーズに分けて実施します。Mark&Sweepは、 GCスレッドが稼動する際にすべてのアプリケーションスレッドが停止するため、GCの負荷が1箇所に集中 されます。 ・Markフェーズ まずRootを全走査し、Rootにしるし(Mark)をつけます。次にヒープ領域のすべての到達可能な「生きてい る」オブジェクトにしるし(Mark)をつけます。 ・Sweepフェーズ しるしのついていないオブジェクトを、ヒープ内から掃きとり(Sweep)ます。このとき、ヒープ領域内すべての オブジェクトに対して走査が行われます。 13 STEP2: Garbage Collection (4/6) Mark&Sweep (Sweep後、十分なメモリ領域が確保できなかった場合) Compaction Phase ¾ ¾ 削除オブジェクトの空きスペースを詰めて連続した空きスペースを確保 Compactionの対象にならないオブジェクトがある z pinnedオブジェクト(=JVMの外側から参照されている、または参照されているように判 断されるオブジェクト) 考慮点 ¾ ¾ ¾ 断片的な空きスペースを詰めることによるFragmentationを解消できる GCの中で最も負荷が高い処理であるため、実行されるGC時間が長くなる 移動できないオブジェクトがある場合は、生成される空き領域が複数になり、フラ グメンテーションが発生する 14 ・Compactionフェーズ ヒープ上に存在しているすべてのオブジェクトをヒープのアドレス領域の一端にまとめる作業が行われま す。MarkフェーズとSweepフェーズはそれぞれそれほど大きな負荷とならないため毎回のGCで実施され ます。それに対してCompactionフェーズはオブジェクトの移動が伴うため個々のオブジェクトのコピーとメ モリアドレス情報の再構成が行われます。そのため先の二つのフェーズと比べると負荷の大きな作業にな るため、Compactionフェーズは発生条件が整ったときにのみ実施されます。例えばMark&Sweepが行われ た後にヒープ・アロケーションを行えるだけの十分な空き領域が確保できなかった場合や、解放できた領 域が少なくて全体の空き領域が一定以下だった場合です。また、実際にはCompactionの際に動かせな い(Pinned)オブジェクトが存在します。その場合、空き領域が複数に分かれて存在することになります。 コンパクションを行わないオプション-Xnocompactgcも提供されていますが、以下の場合においては-Xnocompactgcは無視さ れます。 明示的に-Xcompactgcが定義されている場合 ・ ・Sweep phaseでリクエスト・オブジェクト割り当てに必要な空きスペースが無いと判断された場合 ・System.gc()が実行され、かつ前回のGCでCompactionが行われなかった場合 ・Active heapの空き領域が5%未満もしくは128KB未満の場合 14 STEP2: Garbage Collection (5/6) Copying 二つの領域を交互に使ってGC処理を行う。 ¾ ¾ ¾ 到達可能オブジェクトだけマーク マーク済オブジェクトを別に用意した領域にコピーし再配置 不要なオブジェクトが存在する状態で、領域ごとすべて解放 Space① root Space② c a (free) b 到達可能オブジェクトのみSpace②にコピーされ再配置される Space① Allocate Space Space① (free) root a Space② b c b c root a Space② 15 Copying方式では二つの領域を用意して、交互に領域の役割を与えGCを行います。まず、片方の領域で ヒープ割り当てを行います。割り当てに失敗するとGCが開始され、使用中のオブジェクトにMarkします。こ のMarkするところまではMark&SweepのMarkフェーズと同様です。Copyingでは、このMarkフェーズ以降 の動きが異なります。Markされたオブジェクトは未使用であったもう片方のヒープ領域にコピーされ、さら にもともと空領域だったためアドレスの端からオブジェクトを再配置します。すべての到達可能なオブジェ クトがコピーされたところで、元のヒープ領域は不要オブジェクトのヒープ領域ごと廃棄され空領域となりま す。その後は、コピー先で割り当てに失敗するとGCが発生し、同じサイクルで各ヒープ領域の役割が交代 します。 15 STEP2: Garbage Collection (6/6) Copying 考慮点 ¾ ¾ フラグメンテーション回避 Mark&Sweepなどと比べてallocate処理が早い z ¾ ¾ フリーリスト不要のため 使用できるメモリー領域が分割されるため、メモリ領域が多く必要 オブジェクトの移動により、ポインタの書き換えが起こるため、GC時間は Mark&Sweepよりも長い 16 Copyingでは、メモリー解放後のヒープには常に連続した空き領域が確保されている状態になります。そ のため、Mark&Sweepのように空き領域の検索作業が不要になります。つまり通常のリクエスト処理のパ フォーマンスが向上します。また、ヒープ領域全体が空き領域になるのでフラグメンテーションも回避する ことができます。ただし、良いことばかりではありません。常に余分の空き領域を持っている分OSに対して 要求するヒープ用のアドレス空間は大きくなります。また、オブジェクトのコピーとアドレスの付け替えがGC の度に起こるので、GC時間はMark&Sweepよりも長くなります。 16 STEP3: Heap Expansion ヒープ拡張 GC処理後に十分な空きスペースが無い場合に実行 ¾ 拡張中は全てのアプリケーション・スレッドは停止状態となる 最小・最大ヒープサイズを同じにした場合、無効となる ¾ ヒープ領域確保できなかった場合は、OutofMemory発生 ¾ z ただし、最小ヒープサイズに対してGCは起こるので、パフォーマンス低下する heap 拡張 最小ヒープサイズ(-Xms) 最大ヒープサイズ(-Xmx) 発生トリガー ¾ 最小空きヒープ領域( -Xminf )よりも小さくなった場合 GC時間が稼動時間の13%を上回った場合 ¾ オブジェクトのAllocationに失敗 ¾ z ただし、このパーセンテージは過去3回分が対象 17 GCの発生後、Allocationを行えるようにするためJVMはヒープ領域の拡張を試みます。この際の拡張サイ ズは最大ヒープ領域(-Xmx)にて指定したヒープサイズを限度として行われます。拡張を実行しても十分 な空き領域が得られなかった場合はOutOfMemoryとなります。拡張は負荷の高い処理であるため拡張を 無効にすることも可能です。無効にする場合は最小ヒープサイズ(-Xms)と最大ヒープサイズ(-Xmx)を同 じ値に設定します。しかし、最小ヒープ・サイズを大きい値に設定すると、最初のGCに非常に長い時間が かかってしまいパフォーマンスが低下することから推奨はされていません。 ヒープ拡張の発生トリガーは次のとおりです。 ①Java heapの空き領域が最小空きヒープ領域よりも小さくなった場合 最小空きヒープ領域(-Xminf)のデフォルトは0.3であるため、Java heapの30%を空き領域として確保できる まで拡張は行われます。このとき、拡張しなければいけないサイズが最大拡張サイズ(-Xmaxe)よりも大き い場合には、最大拡張サイズ分だけ拡張します。最大拡張サイズのデフォルトは無制限です。一方、拡 張しなければいけないサイズが最小拡張サイズ(-Xmine)より小さい場合には最小拡張サイズ分を拡張し ます。デフォルトは1MBです。 ②GC時間が稼動時間の13%を上回った場合 GC時間がアプリケーション稼動時間の13%(※)を上回った場合は、GC時間が長くなっているとJVMが判 断し最小拡張サイズ分だけヒープを拡張します。拡張後の空き領域の割合は最大ヒープ空き領域を超え ることはありません。最大ヒープ空き領域のデフォルトは60%です。 ③オブジェクト割り当て失敗 どのような状況にしても、Allocationに失敗した場合には、リクエスト・オブジェクトが格納できるサイズ分が 拡張されます。 (※) ・JDK1.5/1.6の場合 パーセンテージ = [過去3回の合計GC処理時間 / (過去3回の合計GC処理時間 + 過去3回の合計GC非 処理時間)] * 100 ・JDK1.4.2の場合 パーセンテージ = [(過去3回の合計GC処理時間) / (過去3回の合計GC非処理時間)] * 100 17 STEP3: Heap Shrinkage ヒープ縮小 GC後、必要以上にヒープが大きくなった場合に実行 最大ヒープ空き領域が60%以上の状態 最大ヒープ空き領域が60% heap 縮小 最小ヒープサイズ(-Xms) 発生トリガー ¾ 最大ヒープ空き領域( -Xmaxf:デフォルト60%)を上回っている、かつ、以下 の条件がすべてtrue z JVMによるGC 9 9 9 z GCにて必要な空き領域が確保できている 最大ヒープ空き領域を100%に設定していない 過去3回のGCでheap expansionが発生していない System.gc() 9 GC開始時の空き領域の割合が最大ヒープ空領域以上である 18 GCによる空き容量の確保の結果、ヒープが必要以上に大きくなった場合は最小空きヒープ領域(-Xms) で指定した最小値を限度としてヒープの収縮が行われます。ヒープ収縮が実施される条件は最大ヒープ 空き領域(デフォルト60%)を上回っており、チャートの条件がすべてtrueになった時のみです。縮小され たヒープは最小ヒープサイズ(-Xms)よりも小さくはなりません。 また、ヒープ縮小処理前に以下の全ての条件がtrueの場合はCompactionが実施される場合があります。 ・直前のGCでCompactionが発生していない ・ヒープ後半に(断片化されている)空き領域が存在していない、もしくはヒープ後半に(断片化されてい る)空き領域の合計サイズが縮小するサイズの10%以下である ・前回のGC処理にて、Compactionも縮小処理も発生していない 18 3. GCポリシー 19 この章では、WASで設定可能なGCポリシーについて説明します。 19 GCの実施方法および形態 GCポリシーは異なるGC実施方法と形態からなる GC実施方法 GCポリシー (デフォルト) ①Throughputの最適化 ②Pause Timeの最適化 ③Subpool ④世代別 Nursery Tenured JVMオプション -Xgcpolicy:optthruput -Xgcpolicy:optavgpause - Xgcpolicy:subpool -Xgcpolicy:gencon Stop the world GC形態 concurrent Mark&sweep ○ Copying ○ ○ ○ ○ ○ ○ ○ ○ ○ 20 ヒープ割り当てやGCのアルゴリズムについてはこれまで沢山の研究が行われてきており、多種多様な手 法がこれまで生み出されています。WAS V7.0で使用されているJ9 VMではチャートにあるように4つのGC ポリシーが利用可能となっています。WAS V7.0で使用されるIBM JREでのデフォルトはこれまでのIBM JREと同様で、Optimize for Throughput (Mark&SweepでSTW)となっています。これらの指定は、WASの Java仮想マシンに対する設定(汎用JVM引数)で行います。 20 GC実施方法 – Stop the world Stop the world GCスレッドでGC処理を実施 GC実施中はアプリケーションスレッド停止 リクエスト処理 アプリケーション・スレッド リクエスト処理 GC処理 GC 開始 GCスレッド GC 終了 アプリケーション・スレッド すべてのアプリケーショ ン・スレッド停止 アプリケーション正常稼動 アプリケーション応答なし アプリケーション正常稼動 21 ここから「誰が何時GCを行うか」の説明を行います。まずはデフォルトのStop The World(STW)方式です。 GCはヒープ割り当てが失敗したときに発生します。その際、割り当てに失敗したJavaスレッドがGC作業を 引き続き行うのですが、STW形式ではGCが開始された直後に、GCを担当するJavaスレッド以外のスレッド 作業をすべて停止させます。 GC処理が終了するまで他のスレッドは停止させられたままなので、GC作業 を行うJavaスレッドの外では、言わば「世界が止まった状態」であるかのように見えるのでこのようなネーミン グになっています。当然リクエストの処理もGCが終了するまでストップします。 21 GC実施方法 – Concurrent Concurrent GC実施前にリクエスト処理と並行してMark処理を実施 ¾ すべてのアプリケーションが一時停止になる期間を最小にする スループットの低下、応答時間の遅延 ¾ 常時GCスレッドが動いているため、Stop the world方式よりもスループットが低下 する傾向にある(一般的には5-10% ) リクエスト処理 Mark専用スレッド リクエスト処理 GC処理 GCスレッド GC 終了 アプリケーション・スレッド Mark専用スレッド アプリケーション・スレッド すべてのアプリケーショ ン・スレッド停止 アプリケーション正常稼動 アプリケーション応答なし アプリケーション正常稼動 22 Concurrent方式は、Stop the world で問題となっていたアプリケーションスレッドの停止時間をできるだけ 最小にした方式です。この方式を使用すると、Mark処理、Sweep処理、Compaction処理のうち、Mark処理 をアプリケーションスレッドと並行して行います。そうすることで、アプリケーションの停止時間を短くします。 ただし、この方式を使用してもGCによりアプリケーションスレッドが停止する時間は発生します。 具体的には、リクエストの処理中に優先度の低いスレッドをMark処理専用に別途用意し、CPUを利用でき る時間を見つけてMark作業を先行して行います。GCの一部の作業を事前に行うことから、Concurrentで はSTW方式の時よりも、「世界を止めて」GC処理をする時間が理論上短くなります。ただし、これはあくま でも理論上の話で、実際はアプリケーションのデザインやシステムリソース、システムの利用状況などに よって有効性は異なります。最悪の場合はSTWよりも効率が悪くなってしまう可能性もまったくないわけで はありません。また、バックエンドとはいえ通常時にGC作業を先行して行う分、余剰CPU時間があまりない 場合はリクエスト処理のスループットに影響が及ぶ場合もあります(一般に5-10%の性能低下が見られると 言われています)。 22 GC実施方法 – STW& Concurrent (1/2) 世代別GC STW & Concurrent および Copying & Mark&Sweep の併用型 オブジェクト寿命の傾向に着目したGC方式 New領域 ¾ STW&Copying Old領域 ¾ Concurrent&Mark&Sweep 23 世代別GCのポイントはオブジェクトの生存期間に着目した点です。 リクエストの処理のため生成されるオブジェクトのように、一時的な目的のために生成されたオブジェクトは 必要でなくなるまでの期間が短いという特徴があります。 その一方でWASの運用そのものに必要なオブジェクトのようにWASプロセスの生存期間中ずっと必要とな り続けるオブジェクトも存在します。 そこで、ヒープの割り当て領域を行える領域をある特定の領域(New領域)に絞り込むことでGCの発生頻 度を相対的に上げつつ、その中である回数のGCの中を生き延びたオブジェクトはその後も長く必要とな る可能性が高いと判断して、あまりGCをかけない領域(Old領域)に移動させるというのが世代別の方針で す。 ただし、Old領域に移動させたオブジェクトがすべてWASの生存期間中に必要なオブジェクトとなる保障 はないため、Old領域が一杯になったところでOld領域の中の使用されていないオブジェクトの廃棄がかか り、新たなOld領域のオブジェクト候補のためのスペースが確保されます。 23 GC実施方法 – STW& Concurrent (2/2) 世代別GC ①Allocate Space に空きがなくなる Old area (tenured Space) New area (nursery Space) Allocate Space オブジェク ト生成 a b Survivor Space (free) c ②Scavenge GC発生(※1) ③Survivor Spaceにオブジェクトコピー Allocate Space (free) x y z Survivor Space a ④スペースの役割交代 Survivor Space Tenured Space c b Allocate Space a c b (繰り返し①~④が発生) Survivor Space Allocate Space (free) a s z x y z a ⑤あるGC回数(tenure age)を超えるとold領域に移動 24 ※1。Scavenge GC:NEW領域のみを対象とした短時間で終了するガベージ・コレクション New領域は二つの領域に分かれ、一方をAllocate領域、もう一方をSurvivor領域と呼びます。生成される オブジェクトはまずAllocate領域に格納されます。Allocate領域がいっぱいになると、ヒープ内の「生きた」 オブジェクトのトレースが行われます。その際に、「生きた」オブジェクトがあるとそのオブジェクトをSurvivor 領域にコピーをしていきます。これによって、Allocate領域の全体のチェックが終わると、「生きた」オブジェ クトはすべてSurvivor領域にコピーされており、Survivor領域を使ってこれ以降のリクエスト処理を行えるよ うになっています。そこで、Survivor領域が新たにAllocate領域として使用され、元Allocate領域だったもの はSurvivor領域となって次のガーベッジ・コレクションで再び役割が交代するまで放置されます。このNew 領域を使用したガーベッジ・コレクションをScavengeGCと呼んでいます。ScavengerGCが行われている間 は、デフォルトのOptimize for Throughputの時と同じようにすべてのアプリケーション・スレッドは停止しま す。 ある設定された閾値を超えるGCをNew領域で生き延びたオブジェクトはSurvivor領域ではなくTenured領 域にコピーされます。ある程度JVMが稼動し続けていると大抵はTenured領域もオブジェクトでいっぱいに なります。その中には閾値を超えたGCを生き延びたものの、すでにガーベッジとなってしまっているオブ ジェクトも存在します。そこでTenured領域に対してもGCが実施されます。Tenured領域のGCはOptimize for Pause Timeと同じ方式がとられています。これによりTenured領域のGCにかかる時間を短縮します。 GCポリシー名に「Concurrent」とついているのはこのTenured領域に採用されたGCの性質を表しているた めです。 24 世代別GC 世代別GC Tenure age ¾ ¾ Old領域にpromoteすべきオブジェクト年齢のこと JVMによってNew領域の使用率をベースに動的に調整される z z Scavenge GC発生によりこの年齢は増加する 最大14 考慮点 ¾ ¾ ScavengeGCの実行時間はヒープ全体のGC に比べ短いので、プログラムの停止 時間を改善できる。 Old領域でFullGCが発生するとGC時間が長くかかってしまう 25 オブジェクトの「年齢」はどれだけの回数のGCを生き延びたかで判断されます。ScavengerGCが実施され るたびに、JVMは生き残ったオブジェクトにひとつずつ「年齢」を加算して管理を継続していきます。 Tenured領域へは閾値の回数だけ生き延びたオブジェクトのみが移動することができますが、この閾値は 最大でも14です(つまり、タイムアウトをある程度長く設定したHTTPSessionオブジェクトやデータ・ソースの Connectionオブジェクトなどは最終的にTenured領域に格納される可能性が高くなります)。この閾値は New領域内にとどまっているオブジェクトの割合によってJVMが調整を行っていて、生き延びているオブ ジェクトの占有率が10%以下の場合閾値は10に、その後占有率の上昇とともに閾値も上がっていき、占有 率が30%を超えると最大値に到達します。 25 4. GCチューニング 26 ここでは、GCおよびJavaヒープのチューニングについて説明します。 26 GCチューニング GCチューニングの目的 パフォーマンスをあげるために、最適な設定をする GC回数は多すぎても少なすぎてもいけない GC回数が多い ¾ アプリケーション停止が頻発する GC回数が少ない ¾ 1回のGC時間が長くなり、アプリ停止時間が長くなる 27 GCは、Javaにおけるメモリ関連のパフォーマンス・ボトルネックの大きな要因といえます。 そのため、GCが 多すぎるとアプリケーションの停止が頻発し、GCが少なすぎると1回のGC時間が長くなります。 27 GCで注目する点 GCで注目する3つの観点 GC発生頻度 ¾ GCの適切な発生頻度はアプリケーションにより異なる GC時間の長さ ¾ ヒープ・サイズとヒープ内のオブジェクト数に依存。 z z ¾ ヒープ・サイズが小さいと、GCが頻繁 ヒープ・サイズが大きいと、GC発生回数は抑えられるが1回のGC時間が長くなる GC時間は実行時間の5%以内 GC実行後のヒープの状態 ¾ ¾ ヒープが確保できない場合、OutofMemoryエラーを出力する ヒープ領域が拡張と収縮を繰り返すことなく、定常 28 GCで注目する観点は三つあります。1つめがGCの発生頻度、これはGC前後のタイム スタンプを比較す ることで確認することができます。 2つめがGC時間の長さです。このとき、ヒープサイズは小さすぎても大きすぎても最適なパフォーマンスは 得られません。GC時間は実行時間の5%以内になるようチューニングします。GC時間が5%以上で頻発して いる状態の場合は、Javaヒープサイズを増やす必要があります。 ・計算方法 GC実施時間÷最後のオブジェクト割り当て(AF)以降の時間×100 =GC時間 最後にGC後のメモリー領域に着目します。ヒープの状態によっては、ヒープの拡張、縮小が発生しますが、 これらの処理の間、アプリケーションは停止してしまいますので、できるだけ拡張、縮小はおさえたほうがよ いです。また、拡張しても十分なヒープが得られない場合はOutOfMemoryが発生してしまうので、注意す る必要があります。 28 GCポリシーの選択基準 GCポリシー アプリケーション・サーバーの汎用 JVM 引数に-Xgcpolicyオプション で指定 多くの場合、デフォルトのoptthruputの適用が望ましい デフォルトでパフォーマンスがでなかった場合、他のポリシーを検討 GCポリシー 選択基準 (デフォルト) Throughputの最適化 アプリケーションのスループット重視 Pause Timeの最適化 Subpool 世代別 アプリケーションのレスポンスを重視 アプリケーションのスループット重視 大規模SMP環境用にオブジェクト・アロケーショ ン・アルゴリズムを最適化。AIX、Linux PPC、 zSeries、z/OS、i5/OSでのみサポート アプリケーションが生成するオブジェクトが短命 JVMオプション -Xgcpolicy:optthruput -Xgcpolicy:optavgpause Xgcpolicy:subpool -Xgcpolicy:gencon 29 これまでの説明事項をひとつの表にまとめてみました。それぞれのGCポリシーを使用したい場合にJVM へ渡す引数も一緒に乗せてあります。WAS V7.0で使用されるIBM JREでのデフォルトはこれまでのIBM JREと同様で、Optimize for Throughput (Mark&SweepでSTW)となっています。これらの指定は、WASの Java仮想マシンに対する設定(汎用JVM引数)で行います。 29 GCポリシーの選択指針 一部のリクエスト処理は遅くなっても構わないので、大部分のリクエスト処理はでき るだけすばやく行いたい。 処理時間の分布が広くなるのではなく、リクエストに対してはいつでもほぼ同じレス ポンス時間で返したい。 世代別GCの使用を検討する。 世代別GCを使用して、スループットを重視したい -Xgcpolicy:gencon で効率的なヒープ割り当てとGCを行うのが有効です。 大きなヒープサイズを使用したい。 -Xgcpolicy:optavgpause を指定することでconcurrentモードでメモリ管理を行うとよくなる可能性がありま す。 使用している業務アプリケーションは一時オブジェクトを沢山生成する作りになって いる。 デフォルト(-Xgcpolicy:optthruput)が一番良い結果をもたらす可能性が高いです。 New領域は大きく、Old領域を小さくする 世代別GCを使用して、停止時間を重視したい New領域は小さく、Old領域は大きくする 30 最適なGCポリシーはアプリケーションのデザイン、システム構成、および利用状況によって異なります。大 抵のケースではデフォルトのポリシーで十分要件が満たされる場合が多いといわれています。もしデフォ ルトポリシーでうまくいかなかった場合、このチャートをチューニングで試すポリシーの検討材料にしてみ てください。 30 Javaヒープチューニング 目的 JVMが適切にGC処理を行う GCから適切なJavaヒープサイズを判断 ヒープ領域が拡張と収縮を繰り返すことなく、定常 GC終了後に30%以上の空き領域を常に確保 31 JavaヒープのチューニングはGCの状態を確認しながら決定します。本来、ヒープは拡張および縮小を繰 り返すことなく一定の状態であることが望ましく、ヒープ占有率は70%前後が好ましいです。そのような状態 にあるときにGC発生頻度やGC時間が最も安定します。ヒープ状況をモニターするにはverbose:gcを使用 します。 31 Javaヒープのチューニング チューニングの例 ヒープ領域の拡張が頻発する ¾ ヒープ領域がすぐに最大ヒープサイズとなり、GC終了後の空きが30%確保 できていない ¾ ¾ 最大ヒープサイズが大きいので、ヒープサイズを小さくする GCの平均所要時間が13%以上と、発生頻度が高い ¾ ¾ 最大ヒープサイズが小さいので、GC終了後に空き領域が30%確保できるように大きくする ページングを回避するため実メモリで格納できる以上のサイズにはしない 1回のGCの開放量が85%と大きく、GC所要時間が長い ¾ 最小ヒープサイズが小さいので、定常となった値を最小ヒープサイズと設定 GC実施後、空き領域が最小空きヒープ領域(-Xminf:デフォルト0.3)で指定された領域を確保 できないと、ヒープは拡張される GC後に大きい空き領域を確保するため、最小空きヒープ領域(-Xminf)を大きくする GC平均所要時間が3秒を超える場合はヒープ・サイズの調整を検討する。 32 ヒープサイズの設定を行うときの一般的な設定指針を参考として記載します。システムのサービスインを迎 える前までに、この指針に沿って決定した値を出発点としてチューニングを行い、個々のシステムに適切 な値を決定してください。また、GCの平均所要時間は、GCの平均所要時間%=(GC平均所要時 間)/(GCの平均所要時間+GC呼び出し平均間隔)×100、で見積もることが可能です。 32 5. WAS V7.0 64bit版 33 この章では、WASの64bit版と32bit版について説明します。 33 WAS 64bit版の登場 WASモジュール 2種類 ¾ ¾ 32bit版 64bit版 WAS V6.0から64bit版が登場 34 WASモジュールには、32bit版と64bit版の2種類が存在します。 2009年4月時点で最新のWASバージョンは7.0であり、64bit版モジュールはその2つ前のメジャーバージョ ンである6.0から提供されています。64bit版モジュールを導入するためには64bit OS環境が必要となりま す。また、32bit版、64bit版モジュールは別モジュールになるため、32bit版から64bit版に、もしくは64bit版 から32bit版に変更する場合は、再インストールをおこなう必要があります。 34 WAS 32bit版からWAS 64bit版への移行 アプリケーション 32bit環境で動いていたアプリケーションは、そのまま64bit環境へ移 行可能 ただし、JNI (Java Native Interface) を使っているアプリケーションで は、読み込むライブラリーを64bitにしてからリコンパイルを行う 35 32bit版、64bit版において、WAS上のアプリケーションの動作に関する違いは特にありません。32bit環境 で動いていたアプリケーションは64bit環境へそのまま移行することができます。ただし、JNI(Java Native Interface)を使用しているアプリケーションでは、読み込むライブラリー(ネイティブ・モジュール)を64bitのも のにしてからリコンパイルをおこなう必要があります。 35 32bit版 vs 64bit版 選択フェーズ 決定時期 32bit版/64bit版のどちらを使用するかは要件定義までに決定してお く必要がある。 しかし、実際に必要なヒープ容量が確定するのは、テスト時になる 提案 要件定義 基本設計 詳細設計 導入製品 決定 環境構築 ヒープ見積もり 決定 テスト ヒープ チューニング 選択指針 最大ヒープサイズ ¾ ¾ 2GB程度までなら32bit版を選択する 2GB以上、もしくは今後の拡張性を考慮するなら64bit版を選択する 36 実際のヒープサイズがわかるのはテストフェーズになってからですが、導入製品の決定はもっと早い フェーズで実施されます。64bit版モジュールを選択する際の判断基準として、最大ヒープ・サイズが挙げ られます。32bit版モジュールの場合、最大ヒープ・サイズを2GB程度(この値はOSによって若干異なる)ま でしか指定することができません。そのため、お客様要件より1つのJVMでヒープ・サイズを2GB以上必要と することが確定している場合は、64bit版モジュールを選択してください。今後の拡張によりヒープ・サイズ が2GB以上になる可能性がある、または今後の技術動向や拡張性を考慮するのであれば64bit版をお勧 めしております。ただし、ヒープ・サイズはGCの観点から小さい程パフォーマンスは良いので、必要以上に ヒープを大きくすることは推奨しません。 36 64bit版 vs 32bit版 64bit版/32bit版 比較表 64bit版 最大ヒープサイズ 実績 32bit版 備考 ・64bitは無制限 ・32bitは制限あり ・2GBまでなら32bit版のほうがパフォーマンスがよい可 能性が高い ◎ × (~16EB) (~約2GB) △ ◎ ・WAS6.1まで64bitはパフォーマンスが著しく低下した ため、使用が懸念されていた。そのため、実績が少な くなっている ◎ ・WAS V7.0の新機能である参照の圧縮を有効にした 場合、64bitでパフォーマンス改善がみられる 参照の圧縮 OFF メモリー使用量 × 参照の圧縮 ON ○ その他 2GB以下なら、32bit版のほうがパフォーマンスがよい 64bit版は、WASからネイティブ・モジュールを使用して外部接続する 対象が64bit製品である場合に親和性が高い 64bit版は参照の圧縮機能を使用しない場合、メモリー使用量が増加 64bit版でプロファイル作成する場合、コマンドを使用 37 下記32bit版、64bit版のメリット・デメリットを参考に使用するモジュールを選択ください。 ■32bit版 -メリット 実績が多い。 必要なHeapサイズが2GB以下である場合、64bit版と比較してパフォーマンスがよい可能性が高い。 ・デメリット 最大ヒープ・サイズを2GB程度までしか指定できない。 ■64bit版 ・メリット 最大ヒープ・サイズを2GB以上(理論上16EBまで)指定できる。 WASからネイティブ・モジュールを使用して外部接続する対象が64bit製品である場合、親和性が高い(後述の[その他 考慮点]を参照) ・デメリット 実績は32bit版と比較すると少ない。(ただし、64bit版の使用実績は着実に増えている。) メモリアドレス参照に32bit版は4byte使用するのに対し、64bit版は8byte必要となるため、64bit版の方が最大で60%程 度メモリー使用量が増加する可能性がある。また、この理由からプロセッサーキャッシュを有効利用できず、32bit版と 比較してパフォーマンスがダウンする可能性もある。(ただし、メモリー使用量の増加については、WAS V7.0の新機能 である参照の圧縮を使用することにより改善可能。) プロファイル作成時にプロファイル管理ツール(PMT)を使用することができないため、manageprofilesコマンドでプロ ファイルを作成する必要がある。 [その他考慮点] DB2のType2ドライバーを使用する場合や、MQのBinding接続をおこなう際、ネイティブ・モジュールが必要になる場 合があります。このような場合は、WASの環境に合わせたネイティブ・モジュールを使用するように構成してください。 (例: WAS 32bit版であれば、接続するDB2インスタンスが64bitであってもDB2 CLI 32bit版を指定する。) 37 参照の圧縮 (Compressed references) WAS V6.1では64bit版が32bit版よりヒープ使用量増加 64bit版ではオブジェクト参照のポインターが8bytes(32bit版の倍) WAS V7.0 64bit版ではポインターを圧縮することによって必 要なヒープ使用量を削減する機能を実装 ランタイムは内部で 32bit 参照と 64bit ポインタを変換 64bit IBM JDK において、ヒープサイズが約29GB以下(プラットフォー ムごとに異なる)の場合に利用可能 ¾ ¾ ¾ Solaris 64bit JVM、HP-UX 64bit JVM、iSeries Classic 64bit JVMではサポートさ れない CPU使用率が若干増加 最大ヒープサイズが25GBよりも小さいときデフォルトで有効になっている。 38 WAS V6.1の64bit版は32bit版と比較してヒープを多く使用する傾向にありました。これはオブジェクト参照 のポインターサイズが32bit版が4bytesであるのに対して64bit版では8bytesであるのが原因でした。WAS V7.0では64bit版のメモリー使用量を抑える機能として、 64bit版の8bytesの参照を4bytesに圧縮する参照 の圧縮(Compressed references)機能が導入されています。本機能は64bit版の機能となります。参照の圧 縮はメモリー使用量の削減に効果があり、2GB以下のヒープにおけるパフォーマンスも32bit版に近い値を 実現することができます。各プラットフォームの参照の圧縮のデフォルト値は次のページに記載していま す。WAS V7.0で64bit版モジュールを使用する場合は、この機能を有効にすることをお勧めいたします。 38 参照の圧縮:デフォルト値 プラットフォームによる参照圧縮のオプションのデフォルト 値の違い 有効化するには –Xcompressedrefs オプションを使用 WAS V7.0のプラットフォーム 参照圧縮のオプションのデフォルト値 AIX64版 なし Linux64版 あり Windows64版 あり WAS V7.0のFixPack3で、AIX64bitで参照の圧縮がデフォルトOFFが ONに改善(2009_03_26リリース) ¾ 以下の両ケースでデフォルトONとなる z z Fixpack3を適用したのちプロファイルを作成 既存プロファイルがある状況でFixPack3を適用 Fix list for IBM WebSphere Application Server version 7.0 Fix Pack 3 (7.0.0.3) PK75174 Auto-enable compressed refs on AIX PPC64 if heapsize less than 25 gigabytes http://www-01.ibm.com/support/docview.wss?rs=180&uid=swg27014463#7003 39 参照の圧縮機能はプラットフォームによりデフォルト値が異なります。AIXのみデフォルトOFFになっていま すが、製品のバグであるため、FixPack3で有効になるよう改善されています。既存プロファイルにFixPack3 を適用しても、FixPack3を適用したのち新規でプロファイルを作成した場合も、どちらも参照の圧縮機能 は有効になります。 参照の圧縮オプションは、x86アーキテクチャーの64bitでない場合非推奨となっています。 39 6.パフォーマンスの最適化 40 この章では、パフォーマンス向上が期待できるWAS V7.0の機能を紹介します。 40 共有クラスキャッシュ 共有クラスキャッシュとは 複数のJVM間で使用するクラスを共有できるようにする仕組み メリット ¾ ¾ JVMの起動時間の縮小 使用メモリのフットプリント減少 デフォルト有効 ¾ JVM引数に-Xshareclasses:noneを指定することで無効にできる JVMの使用するメモリ JITコードキャッシュ JVM 1 ディスク上の クラス Heap領域 Class Memory Segments Class Memory Segments JVM 2 重複する クラスを 共有 Heap領域 JITコードキャッシュ 41 JVMのパフォーマンス向上の仕組みのひとつとして共有クラスキャッシュがあります。これはIBM JDK V5 で導入されたもので、複数のJVM間で使用するクラスを共有する仕組みです。この機能を用いることにより JVMの起動時間の短縮と使用メモリのフットプリントを減少させることができます。 デフォルトで有効になっており、無効化するにはJVM汎用引数に-Xshareclasses:noneを指定します。 WAS V7 InfoCenter – Java virtual machine settings http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.nd.doc/inf o/ae/ae/urun_rconfproc_jvm.html 41 共有クラスキャッシュ – JDK6での改良点 JDK6ではOS再起動をまたいで共有クラスキャッシュの情 報を保持することが可能 JDK5ではOS再起動の際にキャッシュ情報は消去されていた JDK6ではキャッシュ情報をファイルに書き出すことによりOS再起 動をまたいで情報を保持することを可能にしている JVM汎用引数で設定 ¾ ¾ 有効 -Xshareclasses:persistent 無効 -Xshareclasses:nonpersistent 42 共有クラスキャッシュはIBM JDK 5で導入されましたが、JDK6でいくつかの改良がされています。JDK5 ではOSを再起動させるとキャッシュ情報はクリアされてしまいましたが、JDK6ではファイルに書き出すこと によってOS再起動をまたいでキャッシュ情報を保持させることが可能になっています。これによりOS再起 動後の最初のJVM起動時間の短縮がはかれます。 またJDK6ではキャッシュできるデータタイプも増えています。 Java Diagnostics Guide 6 - Class data sharing command-line options http://publib.boulder.ibm.com/infocenter/javasdk/v6r0/index.jsp?topic=/com.ibm.java.doc.user.aix32.6 0/user/sharedclassesxoptions.html 42 共有クラス・キャッシュ-設定 プラットフォーム別、デフォルト設定 プラットフォー ム パーシスト設定 キャッシュディレクトリー(cashDir) AIX版 なし /tmp/javasharedresources Linux版 あり /tmp/javasharedresources Windows版 あり C:¥Documents and Settings¥<User>¥Local Settings¥Application Data¥Javasharedresources JVM引数に-Xshareclasses:cacheDir=<directory>を指定 43 オプションにcacheDir=<directory> を設定することで、JVM キャッシュ・ファイルの場所を設定変更すること ができます。 Windows版のキャッシュ・ディレクトリーで、Windowサービスによる起動では、<User>はデフォルトで SYSTEM ユーザーとなります。 43 ランタイム・プロビジョニング WASランタイムのパフォーマンス向上 WAS V6.1 ¾ WAS V7.0 ¾ アプリケーション・サーバー起動時にWAS内部コンポーネントすべて起動 必要なWASコンポーネントのみ起動 デフォルト無効 44 WASランタイムのパフォーマンスを向上させる機能として、WAS V7.0からランタイム・プロビジョニングとい う機能が追加されました。V6.1まではアプリケーション・サーバーが起動する際、WebコンテナーやEJBコ ンテナーなど全てのWAS内部コンポーネントを起動していました。V7.0ではランタイム・プロビジョニング機 能を有効にすると、対象アプリケーション・サーバー上のアプリケーションや設定に応じて必要なWASコン ポーネントのみを起動します。例として、アプリケーション・サーバー上にデプロイしている全てのアプリ ケーションがServlet、JSPのみで構成されている場合、EJBコンテナーやWeb Serviceコンポーネントなどは 起動されません。これにより、平均して10%程度アプリケーション・サーバーの起動時間が短縮され、Heap 使用量も減少させることができます。このランタイム・プロビジョニングはデフォルトOFFで、デプロイメント・ マネージャーやノード・エージェント、管理エージェント、ジョブ・マネージャーといった全てのJVMで設定 できます。 44 まとめ・参考文献 45 45 まとめ GCポリシーを選択し、チューニングすることが可能 参照の圧縮により、WAS64bit版もスループットが改善されて いる その他、パフォーマンス向上のための機能として共有クラス キャッシュとランタイムプロビジョニングが提供されている 46 46 参考文献 Information Center WebSphere Application Server V7.0 ¾ http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp ワークショップ資料 WebSphere Application Server V7 アナウンスメント・ワークショップ ¾ http://www.ibm.com/developerworks/jp/websphere/library/was/was7_ ws/ WebSphere Application Server V6.1による基幹システム設計ワーク ショップ ¾ http://www.ibm.com/developerworks/jp/websphere/library/was/was61_guide/in dex.html 47 47