Java SEの次期バージョンであるJDK 12が、機能セットのフリーズに向けた最初の段階に到達した。JDK 12では拡張switch文のプレビューやG1ガベージコレクションのさまざまな改良、そしてShenandoahと呼ばれる新たな試験的ガベージコレクタが提供される。
しかし、JDK 12の大きな提案のひとつであった生文字列リテラルは削除されている。JEPによると、"生文字列リテラルはソースコードの複数行に展開が可能で、\nなどのエスケープシーケンスや、’\uXXXX'形式のユニコードエスケープを解釈しない"。つまり、次のような文字列は、
String html = "<html>\n" +
" <body>\n" +
" <p>Hello World.</p>\n" +
" </body>\n" +
"</html>\n";
このように書くことができる。
String html = `<html>
<body>
<p>Hello World.</p>
</body>
</html>
`;
"... この機能を現在のプレビューの状態に留めておくのは、言語にとって損失です。" この決定について説明したEメールの中で,Brian Goetz氏は次のように書いている。
この機能が言語に取り入れられるまで,もう少し時間を要することになったことはもちろん残念ですが、それでもこれが最善の選択だと考えます。
どのような言語機能であっても,受け取ったフィードバックを検討していく中で,"違うやり方があるのではないか",という意見が少なからずあるのは当然でしょう。ですが,複雑さと表現力のトレードオフを十分に検討した結果であり,現在の設計が現時点で最善の方法であると確信できるまで,十分な設計検討をした結果なのです。リリースを見送ることで,設計を洗練し,さらなる選択肢を検討し,Preview Featureプロセス(JEP 12)の要件を本当に満足するプレビューを目指すことが可能になります。
新たに追加された言語機能という点では,前述のJEP 325: Switch Expressionがプレビュー機能として追加されている。このJEPには,おもに2つのswitchの変更がある。ひとつは"case L->"と記述する新しいラベル形式で,ラベルが一致した場合のみ,ラベルの右側のコードが実行されるというものだ。
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
ふたつめは,switchが式になることを可能にするもので,値を持ったり,あるいは値を返すことが可能になる。
T result = switch (arg) {
case L1 -> e1;
case L2 -> e2;
default -> e3;
};
JDK 12ではさらに,G1ガベージコレクタにもいくつかの大きな機能強化が加えられている。G1の目標のひとつは,コレクションの停止時間としてユーザが指定した目標時間を実現することだが,状況によって,コレクタがこの目標を達成できない場合がある。これは,コレクション中に発生する作業量,すなわちコレクションセットを選択するために,G1がヒューリスティックな方法を用いていることから発生するものだ。しかしながら現状のG1では,コレクションの全領域の全オブジェクトを停止することなく収集せざるを得ない。従って,アプリケーションの動作が変化してヒューリスティックが"stale"データを処理する場合のように,コレクタのヒューリスティックが過大なコレクションセットを選択した場合には,コレクタが目標停止時間を超えることがあるのだ。
ユーザが指定した目標停止時間を達成するために,JEP 344では,to-be-garbage-collected領域(コレクションセットの混合)を必須部分とオプション部分に分割することで,G1のガベージコレクションプロセスを中断できるようにする。休止時間の目標を達成するために必要な場合は,オプション部分のコレクションを中止することが可能になる。
G1の持つもうひとつの問題は,G1がJavaヒープからメモリを返却するのはフルGCまたはコンカレントサイクルのみであるため,コミットしたJavaヒープメモリをオペレーティングシステムに対して必ずしもタイムリに返していない,という点だJEP 346では,次のように指摘している。
G1が可能な限りフルGCを避けることと、Javaのヒープ容量とアロケーション操作に基づいたコンカレントサイクルにのみ実行されることから、明示的に指示されない限り、Javaヒープメモリが返却されることはほとんどありません。
この動作は,特にリソースに課金されるコンテナ環境において不都合です。
このJEPが掲げている目標は、G1ガベージコレクタを拡張して、アイドル時には自動的にJavaヒープメモリをオペレーティングシステムに返却するようにすることだ。
G1の強化という点では。JDK 12にはShenandoahという試験的ガベージコレクタが新たに加わっている。これはJavaスレッドの動作と並行して退避操作を実行することによるGC停止時間の削減を目的とするものだ。
ShenandoahはRed Hatによって開発されたマーク/コピーコレクタで、多くの面でG1に似ているが、大きな違いは退避フェーズ中にBrooksフォワーディングポインタを利用していることだ。基本的なアイデアは、ヒープの各オブジェクトに新たな参照フィールドを設けるというもので、このフィールドはオブジェクト自身か、あるいはオブジェクトが新たなロケーションにコピーされた直後はそのコピーをポイントする。これにより、Mutatorスレッドによるコンカレントなオブジェクト退避が可能になる。
Shenandoahによる停止時間はヒープサイズに依存しないが、パフォーマンス上のペナルティが存在するため、どちらかといえば大規模なアプリケーションに適している。そのアルゴリズムについては、PPPJ2016論文に詳しい。
その他のJDK 12の機能としては、次のようなものがある。
- JEP 334: 主要なクラスファイルとランタイムアーティファクト、特に定数プールからロード可能な定数の名目的記述をモデル化するためのAPIを提案する。このAPIのドラフトはこちらで公開されている。
- JEP 230: Java Microbenchmark Harness(JMH)をベースとした、JDKのパフォーマンスを手軽にテスト可能な、マイクロベンチマークのスイート。
- JEP 340: JDKには、ARM 64-bitをターゲットとした2つのソースセット、すなわち移植版がある。Oracleから寄贈されたarm64と、aarch64である。このJEPは、arm64版に関わるソースをすべて排除して、32bit ARM版と64 bit aarch64版のみにするというものだ。
- JEP 341: Class Data-Sharing(CDS)は、起動時間の短縮とメモリ共有によるメリットを実現する機能である。このJEPによると、HelloWorld実行時の起動時間を32パーセント短縮できる。しかし、CDSの恩恵を受けるには、JDKが提供するデフォルトクラスであっても、余分なステップとしてjava -Xshare dumpを実行しなくてはならない。このJEPでは、デフォルトでCDSアーカイブが生成されるようになる。
JDK 12のリリース候補は2月初旬,GAリリースは3月中旬に予定されている。
この話の詳細
今週のInfoQポッドキャストで,Java言語のアーキテクトであるBrian Goetz氏がWesley Reisz氏に話してくれた。2人の議論は,6ヶ月といカデンツがJava開発にどのような意味を持つのか,という話題から始まり,Java 9から12までの機能のレビューへと続いている。そして最後に,長期的なサイドプロジェクト(AmberやLoomやVahallaなど)と,JDKのより大きなリリースにおけるその役割を論じている。