X

A blog about Oracle Technology Network Japan

Epsilon:JDKの「何もしない」ガベージ・コレクタ

Guest Author

※本記事は、Andrew Binstockによる"Epsilon: The JDK’s Do-Nothing Garbage Collector"を翻訳したものです。


ガベージ・コレクションを行わないJavaメモリ・アロケータのメリット

 

著者:Andrew Binstock

2019年11月21日

 

JDKのパフォーマンス・チューニングは、高度な技術です。多くの場合、最適なガベージ・コレクタを選択してその設定を微調整し、与えられたワークロードに及ぼす影響の最小化を実現することが中心となります。この作業には、常に困難がつきまといます。ガベージ・コレクションをまったく行わなかった場合のワークロード実行速度を知ることが難しいのです。このニーズに対処するため(そして後ほど触れるその他の理由のため)、JDK 11でEpsilonガベージ・コレクタ(GC)が導入されました。このGCでは、JEP 318で定義されているように、メモリの割当ては行いますが、リサイクルは行いません。つまり、ガベージ・コレクションを行いません。
JVMにEpsilon GCを使わせたい場合、コマンドラインで次の2つのランタイム・スイッチを指定する必要があります。

 

-XX:+ UnlockExperimentalVMOptions 
-XX:+ UseEpsilonGC

次のコードについて、上記のスイッチを指定して実行した場合と指定せずに実行した場合とを比較すれば、Epsilonによる影響を確認できます。

パブリッククラスEpsilonDemo {

    public static void main(String [] args){

        final int GIGABYTE = 1024 * 1024 * 1024;
        final int ITERATIONS = 100;

        System.out.println( "開始割り当て...");

        // 一度に1 GBのメモリを割当て
        for(int i = 0; i <ITERATIONS; i ++){
            var array =新しいバイト[ギガバイト];
        }

        System.out.println( "正常に完了しました");
    }
}

このコードでは、100 GBのメモリを割り当てようとしています。行っているのはそれだけです。単に割当てだけを行い、終了しています。Epsilonを指定せずに上記のコードを実行した場合、最初と最後のprintln文に含まれる2つのリテラルが表示されます。つまり、デフォルトのGCが、1 GBのブロックを100個割り当ててから、システムで利用可能なメモリに収まるように、割当て済みブロックのガベージ・コレクションを必要に応じて行ったことを意味します。

しかし、前述のコマンドライン・スイッチを指定してEpsilon GCを使い、上記のコードを実行した場合、プログラムの出力は次のようになります。

割り当てを開始しています...
java.lang.OutOfMemoryError:Java heap spaceによる終了

Epsilonでは以前に割り当てられたメモリのガベージ・コレクションを行わなかったため、ヒープは利用可能なメモリを超過し、あまり見ることがない「Out of Memory」エラーがJDKで発生しました。

このコードを実行するためには、JDK 11以降が必要です。また、利用可能なヒープが100 GB未満でない場合、このとおりの実行結果は得られません。それよりも大きなシステムで実行する場合は、必要に応じてITERATIONS変数を増やすだけで、エラーの発生が可能になります。

パフォーマンスのチューニング作業に限定せずに、デプロイするプログラムにもEpsilonを使いたいという強いニーズがあります。Epsilonチームは、基本的にそのような用途を推奨していませんが、2つの例外は存在します。実行時間が短いプログラムでも、すべてのプログラムと同様、実行終了時にガベージ・コレクタが起動します。しかし、JEP 318で説明されているように、「ヒープの無意味なクリーンアップのためのガベージ・コレクション・サイクルを受け入れることは時間の無駄です。結局のところ、プログラムが終了すればヒープは解放されるからです」。

Epsilonチームは、遅延による影響が特に大きい特定の状況において、Epsilonが使用される可能性があることを予見していました。JEPには、「遅延による影響が非常に大きく、開発者がメモリの割当てを意識してメモリのフットプリントを完全に把握しているアプリケーション、または(ほぼ)完全にガベージ・コレクションが行われないアプリケーションでは、GCサイクルを受け入れることが設計上の問題になる可能性があります」と書かれています。

しかし、上記以外での使用は推奨されていません。ほとんどヒープ領域を使わないことがわかっているプログラムであっても、予期しないメモリの制約があるシステムでEpsilonを使って実行すれば、うまく動作しないリスクがあります。そのため、Epsilonでは、試験運用版機能であることを示すコマンドライン・スイッチが必要となっています。厳密に言えば、EpsilonはJDK 11(およびそれ以降のJDK)に必ず含まれるものですが、コマンドライン・スイッチに含まれる「Experimental」という言葉で、試験運用版機能であることを思い出すはずです。
最後にパフォーマンス・チューニングに話を戻します。ガベージ・コレクションによってプログラムのパフォーマンスがどのくらいの影響を受けているかを知りたいと思ったことがあったのなら、その解決策はEpsilonです。


アンドリュービンストック

Andrew Binstock(@platypusguy):Java Magazineの前編集長。Dr.Dobb's Journalの元編集長。オープンソースのiText PDFライブラリを扱う会社(2015年に他社によって買収)の共同創業者。16刷を経て、現在もロング・テールとして扱われている、Cでのアルゴリズム実装についての書籍を執筆。以前はUNIX Reviewで編集長を務め、その前にはC Gazetteを創刊し編集長を務めた。妻とともにシリコン・バレーに住んでおり、コーディングや編集をしていないときは、ピアノを学んでいる。

 

 
 

 

 

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.