JavaのGCログのローテーション

Oracle JDKの7u2以降、GCログがローテーションできるようになりました。また、JDK8および、JDK7のPSUリリース*1である7u76では、GCログのファイル名にプロセス番号と日時が含められるようになりました。7u76以外、特に目新しい話ではありませんが、備忘のために整理しておきます。

関連するissuesは次の2つです。

JDK-6941923: RFE: Handling large log files produced by long running Java Applications
  • 対象バージョン: 6u34, 7u2, 8
  • GCログがローテーションできるようになった
JDK-7164841: Improvements to the GC log file rotation
  • 対象バージョン: 7u76, 8
  • 最新のファイルの末尾に「.current」が付くようになった
  • GCログのファイル名にプロセス番号(%p), JVM起動日時(%t)が含められるようになった

JDK-6941923: GCログのローテーション

JDK7u2以降、GCログはファイルサイズを基準にローテーションできるようになりました。関連する起動オプションは次のとおりです。

-Xloggc:<ファイルパスのベース>
これは前からありました。GCログのファイルパスを指定します。ローテーションを行う場合、実際のファイル名はここで指定したパスの後ろに連番がつきます。
-XX:+UseGCLogFileRotation
ローテーションすることを指示します。
-XX:NumberOfGCLogFiles=<世代数>
指定した世代数のファイルを残します。
-XX:GCLogFileSize=<1ファイルのサイズ>
8kとか10mとかいった具合に指定します。

たとえば、次のようにJavaプログラムを起動した場合。

java -Xloggc:gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=100k MaximumConsumption

次のファイルにGCログが出力されます。

現在どのファイルに書き込んでいるのか、ファイル名からだけでは分かりません。ファイルの更新時刻あるいは中身を見る必要があります。

JDK-7164841: GCログのファイル名の改善

JDK8および、JDK7のPSUリリースであるJDK7u76では、GCログのファイル名に関して次のような改善がありました。JDK7のCPUリリース*2であるJDK7u75には、この変更は含まれていません。

  • 現在出力されているGCログのファイル名に「.current」が付くようになった。
  • -Xloggcで指定するファイル名に「%p」を含めると、JVMのPIDに展開されるようになった。
  • -Xloggcで指定するファイル名に「%t」を含めると、JVMが起動された日時 (例: 2015-01-31_18-05-24) に展開されるようになった。
  • -Xloggcで指定するファイル名は、「%p」と「%t」の他は、次の文字クラスに制限されるようになった: -_.A-Za-z0-9 *3

たとえば、次のようにJavaプログラムを起動した場合。

java -Xloggc:gc.log-%t -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=100k MaximumConsumption

出力されるGCログは次のようになります。

  • gc.log-2015-01-31_18-03-25.0
  • gc.log-2015-01-31_18-03-25.1
  • gc.log-2015-01-31_18-03-25.2
  • gc.log-2015-01-31_18-03-25.3.current
  • gc.log-2015-01-31_18-03-25.4

この場合、「gc.log-2015-01-31_18-03-25.3.current」が現在出力されているGCログです。以下、2→1→0→4の順に古くなります。

%pと%tの展開は、ローテーションと関係なく使えます。

サンプルプログラム

無意味にヒープを消費してGCを起こすプログラム。

public class MaximumConsumption {
    public static void main(String[] args) {
        for (int i = 0; i < 100_000; ++i) {
            byte[] dummy = new byte[1_000_000];
        }
    }
}

*1:PSU: 機能改善のパッチを含むリリース。

*2:CPU: セキュリティパッチのみを含むリリース。

*3:7u_76にアップデートしたところ、既存の起動スクリプトが使えなくなったので、この変更に気づきました。