アプリケーションが処理できる時間は減ってしまいます。
停止時間を改善するために考えなければいけないのは、次の2つです。
- スループット(処理量)
- レスポンスタイム(応答時間)
たとえば、図8のように、処理1回あたりが0.1秒で終わる、つまりレスポンスタイムが0.1秒だったとします。単位時間を1秒とすると、1秒間に10回実行できるため、スループットは10になります。
なお、処理の実行中には新たな処理のリクエストが来ず、処理が終わったタイミングで次の処理が来るものとします。
しかし、実際はどこかのタイミングでGCが実行され、アプリケーションが停止されます。
図9は、処理中にGCが発生した場合の例です。途中にGCが2回、計0.2秒間実行され、処理の途中でもGCが実行されています。
前述のとおり、GCによる停止時間内では、アプリケーションの処理が停止します。そのため、GCが発生すると単位時間あたりの処理できる時間が短くなり、スループットが低下します。また、アプリケーションの処理途中にGCが実行された場合、処理中のアプリケーションのレスポンスタイムが大きくなります。
例では、レスポンスタイムは8回中7回は0.1秒でしたが、最大は0.2秒です。単位時間を1秒間とすると、スループットは8です。
停止時間に対する2つのアプローチ
停止時間に対処するには、どうすれば良いのでしょうか?
アプローチの方法は、「スループットの向上」と「レスポンスタイムの短縮」のどちらを重視するかで、それぞれ以下のようになります。
スループットを向上させたい場合
バッチ処理のように、1回のレスポンスタイムの短縮よりもアプリケーションのスループットを向上したい場合は、停止時間の総和が小さくなるようにします。
図9で「スループットが要件に比べて低く、スループットを向上させなければいけない」というシチュエーションを考えてみましょう。その場合、図10 停止時間の総和が小さくなるようにすることで、スループットを向上させることができます。
図10では、GCの回数は減り、1回あたりのGCの停止時間は長くなっていますが、総和は小さくなりました。その結果、スループットは8から8.5に向上しました。
レスポンスタイムを短縮したい場合
オンライン処理のように、レスポンスタイムを短縮したい場合は、1回あたりの停止時間が小さくなるようにします。
図9で、レスポンスタイムの要件が0.2秒未満、そして要件を満たしていないレスポンスがあったとします。その場合は、図11のように、1回あたりの停止時間を小さくすることでレスポンスタイムを短縮することができます。
停止時間の総和は2秒と変わりませんが、GCの回数は増えました。そのため、1回あたりのGCの停止時間は短くなっています。
結果として、6回のレスポンスタイムは0.1秒で、2回のレスポンスタイムは0.15秒にできました。
停止時間の総和は変わっていないため、スループットには変化はありません。これでレスポンスタイムの要件であった0.2秒未満を満たすことができました。
これらの例のように、GCでは「実行頻度と停止時間の組み合わせ」を考慮する必要があります。
JVMのGCの実装はたくさんあるので、すべて把握するのは非常に困難です。そのうえ、実際のシステムでは、JVMを選べる機会はあまりありません。しかし、問題を解決するためには、使用するJVMにどのようなGCが実装され、どのように対処すればいいかを判断しなければならないのです。
次回からは、GCとスレッドの関係を解説していきます。お楽しみに。