監視業務によくあるシステムのプロセス再起動はなぜ必要なのか?
GC処理が発生するタイミング
それでは、そのCG処理は、いつのタイミングで発生するのだろうか。図4を見てみよう。
世代の新しいオブジェクトを格納する「Javaヒープ領域」は、必要としないオブジェクトが生成される一時的な領域なので、常に新しいオブジェクトがnew()され続け、また短時間でいらなくなったメモリー領域の残骸が発生し続ける領域だ。したがって、この領域では、頻繁にGC処理が発生することになる。
このGC処理を行うには、先に述べた領域管理テーブルを参照する必要があるので、この管理テーブルに格納されている「エントリー数」が少なければ少ないほど、GC処理にかかるオーバヘッドは少なくなる。このようにエントリー数を少なく維持しようとすると、GC処理の頻度を上げるほかないのだ。このため、新しい世代用の管理領域は、頻繁にGCが発生するので、JVMでは、優先順位の低いスレッドとして実装されている。こうすることで、JavaVMの処理が軽い、つまり本来の処理をしていないアイドル時間を使って、裏でこまめにGC処理が動作する。こうして何度もGCが行われるなかで、あるオブジェクトが生き残り続けると、どこかのGCのタイミングで、世代の古いオブジェクト用ヒープ領域に移される(図5)。
「Javaプログラムで再起動を行う」ことの意味
こうして徐々に、世代の古いオブジェクト用ヒープ領域にもオブジェクトが蓄積されていく。一般的に、このヒープ領域用にはメモリーを大きく確保しておき、空き容量が不足しないように運用するが、それでも長期間稼働するうちに、空き容量がなくなってしまうこともある。
そうなると、本来の処理を行っているスレッドをすべて止めて、対象となるメモリー領域にロックをかけ、「再配置」「アドレスつけかえ」「管理テーブルのメンテナンス」などを行う必要が生じる。これが、「FullGC」と呼ばれるもので、これが発生すると、メモリーの状況により、どのぐらいこの処理に時間がかかるかが一切わからないので、しばらくの間、システムとしての処理が止まってしまうのである。このことで、システムそのもののレスポンスが悪くなったり、場合によってはまったく反応しなくなったりといったことが発生する。このことが、システム運用上、トラブルではないにもかかわらず、システムトラブルと同等の症状を引き起こすこととなり、システム運用の現場では悩みの種なのである。
このように、「Javaプログラムで再起動を行う」のは、Full GCが発生する前に、システムそのものを1から再起動してメモリー空間を綺麗な状態に戻し、Full GCを発生させないために行う、“トラブル予防の一環”なのである。