大きな新機能
Java Platform Module System
1.シンプルにちょっと試してみる。
.
└── src
└── com.sample
├── com
│ └── sample
│ └── Main.java
└── module-info.java
package com.sample;
public class Main {
public static void main(String[] args) {
System.out.println("Hello Modules!");
}
}
module com.sample { }
2.コンパイル
srcと同じディレクトリで実行します。
modulesというディレクトリが生成されてモジュールがコンパイルされる。
dオプションでコンパイル先を指定し、module-info.javaとソースファイルを指定する。
javac -d modules/sample src/com.sample/module-info.java src/com.sample/com/sample/*
├── modules
│ └── sample
│ ├── com
│ │ └── sample
│ │ └── Main.class
│ └── module-info.class
└── src
└── com.sample
├── com
│ └── sample
│ └── Main.java
└── module-info.java
3.実行
java --module-path modules -m com.sample/com.sample.Main
Hello Modules!
JEP 223: New Version-String Scheme
- バージョンナンバーのつけ方が変わったようです。
{$MAJOR.$MINOR.$SECURITY.$PATCH}
localhost:[jdk9] user$ java --version
java 9.0.1
Java(TM) SE Runtime Environment (build 9.0.1+11)
Java HotSpot(TM) 64-Bit Server VM (build 9.0.1+11, mixed mode)
- 9がメジャーバージョン番号
- 0がマイナーバージョン番号
- 1がセキュリティアップデート番号
- +11がパッチ番号
What’s New for Tools in JDK 9
JEP 222: jshell: The Java Shell (Read-Eval-Print Loop)
いわゆる、R : Read 読んで、E : Eval 評価して、P : Print 出力して、L : Loop 繰り返す.
ちょっとしたコードのjavaを実行するまでいちいちコンパイルするのが面倒だから!という容易に実行できる環境です。
他の言語でいうところの対話モードですね。
終了するときは/exit
です。
localhost:[jdk9] user$ jshell
| JShellへようこそ -- バージョン9.0.1
| 概要については、次を入力してください: /help intro
jshell> System.out.println("Hello world.")
Hello world.
jshell>
JEP 228: Add More Diagnostic Commands
jcmdが強化されました。
JEP 238: Multi-Release JAR Files
複数バージョンのJVMで実行できる単一アーカイブjarファイルが作成できます。
こんな感じ。
META-INF/
META-INF/MANIFEST.MF
JavaSample.class
META-INF/versions/9/JavaSample.class
JEP 245: Validate JVM Command-Line Flag Arguments
jvmのフラグ引数のチェックを行うようになった。地味に助かる。
localhost:[jdk9] user$ java -XX:AllocatePrefetchStyle=5 -version
intx AllocatePrefetchStyle=5 is outside the allowed range [ 0 ... 3 ]
Improperly specified VM option 'AllocatePrefetchStyle=5'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
JEP 282: jlink: The Java Linker
モジュールとjlinkを使うことでアプリケーションを含んだ配布用のJVMを生成することが可能です。
つまり、javaアプリケーションと実行環境の最小セットが作成できるわけです!!
jvmが無い環境にデプロイする時に便利ですね。
What’s New for Javadoc in JDK 9
JEP 221: Simplified Doclet API
Docletを作るAPIが新しくなったので、あたらしいAPI使うようにしましょうということです。
com.sun.javadocはやめる。
Module java.compiler#Package javax.lang.model
Docletを使ったツールなどを作っていたり、メンテしている場合は置き換えが必要ですね。
JEP 224: HTML5 Javadoc
JavadocがようやくHTML5で出力できるようになりました!!
オプションをしていない場合、HTML4がデフォルト出力ですが、オプションでHTML5で生成できます。
javadoc -html5 foo bar
JEP 225: Javadoc Search#
JDK 9ではJavadocに検索ボックスができる(ブラウザの検索や、grepしなくても良い!)
JEP 261: Module System
もちろん、Javadocの方もモジュールシステムのサポートをしています。
モジュール定義の中のアノテーションにも対応しています。
--module-path, --upgrade-module-path, --module-source-path
What’s New for the JVM in JDK 9
JEP 165: Compiler Control
JITコンパイラに対する細かい制御ができます。
定義ファイルはJSONで記述します。
-XX:CompilerDirectivesFileで指定するものと同じです。
jcmd {PID} Compiler.directives_print
でコンパイルオブションを確認できます。
JEP 197: Segmented Code Cache
(引用:https://www.voxxed.com/2016/11/java-9-series-segmented-code-cache/ 日本語訳)
コードキャッシュ
メソッドが実行時に最初に呼び出されるとき、それは解釈されます。 JVMには、各メソッドの呼び出し回数がインクリメントされています。コール・カウントが特定のしきい値に達すると、メソッドがコンパイルされます。頻繁に呼び出されないと、カウンターが崩壊します。
コンパイルされたメソッドが最初に呼び出されると、新しい呼び出しカウントが作成され、インクリメントされます。このコール・カウントが特定のしきい値に達すると、最適化を使用して再度コンパイルされます。これは、利用可能な最適化がなくなるまで繰り返されます。
これにより、起動時にすべてのコードをコンパイルして最適化する必要なく、パフォーマンスが向上します。また、最も頻繁に呼び出されるメソッド(「最もホットな」メソッド)が最も高度に最適化されていることを保証します。この動作を確認するには、-XX:+ PrintCompilationを有効にして、メソッドまたはループがコンパイルされるたびに一連の情報を出力します。
メソッドがコンパイルされると、アセンブリ言語命令がコードキャッシュに格納されます。これは固定サイズ(チューニング可能)を持ち、いっぱいになると、JVMはもうコードをコンパイルできません。
階層化されたコンパイルを使用すると、メソッドがコンパイルされる5つのレベルがあります。
解釈されたコード
シンプルなC1コンパイル済みコード
制限付きC1コンパイル済みコード
完全なC1コンパイル済みコード
C2コンパイル済みコード
段階的なコンパイルでは、コンパイルされたコードと新しいコンパイルされたコードの種類があります:プロファイリングされたコード。これには、定義済みで寿命が限られています。
コードキャッシュを分割する提案は、
非メソッドコード(JVM内部の非メソッドコード、例えばコンパイラバッファ、バイトコードインタープリタ)これは永久にキャッシュにとどまります。
プロファイルされたコード(短い寿命で軽く最適化されている)
プロファイルされていないコード(完全に最適化されているため、潜在的にコードキャッシュに永遠に残る可能性があります)
現在、コードキャッシュはコードタイプを区別しません。
キャッシュのフラッシュ
クラスをアンロードするとコードキャッシュからメソッドが削除され、より多くの領域が解放されます。次の場合にはスイーパーが関わっています:
コードキャッシュがいっぱいになっています
最後の掃引以降、十分な状態変化があります
しばらくの間スイープはありませんでした
これは、連続した掃引の段階を経てメソッドを進めるため、安全にフラッシュすることができます。
コードキャッシュ内に同種のコードスープを持つ問題は、非メソッドコードのようないくつかのエントリが決してフラッシュされないにもかかわらず、スイーパーがすべてのコードをスキャンする必要があることです。
解決方法
JEP 127は、対応する3つのコードヒープを作成して、3つの異なるトップレベルタイプのコンパイル済みコードを反映します。 respecitveヒープのサイズをバイト単位で調整するコマンドラインスイッチもあります。
-XX:NonProfiledCodeHeapSize:プロファイルされていないメソッドを含むヒープ。
-XX:ProfiledCodeHeapSize:プロファイリングされたメソッドを含むヒープ。
-XX:NonMethodCodeHeapSize:非メソッドコードを含むヒープ。
したがって、コードキャッシュスイーパーは、メソッドコードヒープに対してのみ反復処理を行うことができます。唯一の問題は、ヒープのサイズを固定しておくとメモリが浪費され、セグメンテーションを無効にするオプション(コードキャッシュの既存のフォームに戻すオプション)が追加されることです。
つまり、プロファイル状態によって、コードキャッシュの領域を使い分けて効率よく処理しようということです。(雑な言い方ですが)
メモリの使い方に似てますね。(JVMインタプリタ特有の課題ですが・・・)
JEP 276: Dynamic Linking of Language-Defined Object Models
(引用:http://openjdk.java.net/jeps/276 日本語訳)
このJEPでは、"プロパティを読み取り"、"プロパティの書き込み "、"callableオブジェクトの呼び出し"といった、invokedynamicのCallsitesと呼ばれる、オブジェクトへのハイレベルな操作をリンクするための機能」を提供します。こうしたプレーンなJavaオブジェクトに対するこうした操作の通常のセマンティクスのためのデフォルトリンカだけでなく、言語固有のリンカのインストールのためのファシリティも提供します。
Nashorn JavaScriptエンジンではすでに、プロパティのリンク、インデックスによるアクセス、スクリプトオブジェクトだけでなく、「外部」「ホスト」Javaオブジェクト(POJOs)への呼び出しのためにdynalinkライブラリを使っています。JEP-276を使用し、"jdk,dynalink"と命名されたJava 9モジュールのパブリック(JDK固有の)APIとしてdynalinkを公開します。
What’s New for JVM Tuning in JDK 9
JEP 158: Unified JVM Logging
これまで、JVMのログはオプションが複雑だったり、種類によっては出力内容に一貫性がなく容易に読み取るのが難しかったです。
フレームワークを導入し、統一のロギングを導入することで、ロギングに一貫性をもたせ、ログを解析しやすいようにするものです。
いままでのGCログは正直、見やすいとは言えなかったですね。
JEP 214: Remove GC Combinations Deprecated in JDK 8
JDK 8で既に非推奨となったGCの組み合わせを削除されました。
DefNew + CMS : -XX:-UseParNewGC -XX:+UseConcMarkSweepGC
ParNew + SerialOld : -XX:+UseParNewGC
ParNew + iCMS : -Xincgc
ParNew + iCMS : -XX:+CMSIncrementalMode -XX:+UseConcMarkSweepGC
DefNew + iCMS : -XX:+CMSIncrementalMode -XX:+UseConcMarkSweepGC -XX:-UseParNewGC
CMS foreground : -XX:+UseCMSCompactAtFullCollection
CMS foreground : -XX:+CMSFullGCsBeforeCompaction
CMS foreground : -XX:+UseCMSCollectionPassing
JEP 248: Make G1 the Default Garbage Collector
32/64ビットサーバ設定のデフォルトGCをG1にします。
Parallel GCなどのスループット重視コレクタよりも、G1などの低停止時間コレクタへの移行でパフォーマンスがよくなる。(といいな)
JEP 271: Unified GC Logging
GCロギングをJEP158に基づき、修正しています。
JEP 291: Deprecate the Concurrent Mark Sweep (CMS) Garbage Collector
Concurrent Mark Sweep(CMS)ガベージコレクタを非推奨にして、今後のメジャーリリースでのサポートを停止する予定です。
オプションで使っている場合は別の手段を検討してください。
What’s New for Internationalization in JDK 9
JEP 267: Unicode 8.0
プラットフォームAPIがUnicode v8.0に対応しました。
以下のパッケージでサポートしています。
Character and String in the java.lang package,
NumericShaper in the java.awt.font package, and
Bidi, BreakIterator, and Normalizer in the java.text package.
JEP 252: CLDR Locale Data Enabled by Default
デフォルトでは、Unicode ConsortiumのCommon Locale Data Repository(CLDR)のロケールデータを使用します。
CLDRロケールデータは、JDK 8の時点でJREにバンドルされていますが、デフォルトでは有効になっていません。
これを有効にするには、エンドユーザーは明示的にシステムプロパティjava.locale.providersを設定する必要があります。
java.locale.providers = JRE、CLDR
JEP 226: UTF-8 Properties Files
キタキタ!マルチバイト言語圏には地味に嬉しい対応です。
PropertiesファイルにUTF8エンコードが利用できます。
UTF-8エンコードのプロパティファイル用のフォーマットを定義し、ResourceBundleがそのフォーマットをロードできるように拡張します。
ISO-8859-1じゃなくて、UTF8で読み書きします。
UTF-8とISO-8859-1はASCII文字と同じエンコードを持ち、人間が読める非ASCII ISO-8859-1エンコードは有効なUTF-8ではありません。無効なUTF-8バイトシーケンスが検出された場合、JavaランタイムはISO-8859-1のファイルを自動的に読み込みます。
問題がある場合は、次のオプションを検討してください。
プロパティファイルをUTF-8エンコーディングに変換します。
次の例のように、プロパティファイルのエンコーディングのランタイムシステムプロパティを指定します。
java.util.PropertyResourceBundle.encoding = ISO-8859-1
まとめ Java9のwhat's newを調べたり、検証してみたりして。
モジュールシステムがフィーチャーされてますが、他にもコレキタ!的な改善が入っていてJava9に移行しない理由は見当たりませんでした。
個人的にはJVMロギングの改善がすごく良いと思いました。
(パフォーマンスチューニングに利用したり、問題調査に非常に役に立つ&内部の動作を知ることができる)
そして、さようなら、native2ascii
参考文献
javase9 what's new
Java Platform Module System.
- http://openjdk.java.net/projects/jigsaw/quick-start
- http://www.oracle.com/webfolder/technetwork/jp/javamagazine/Java-JF16-Java9Modules.pdf
What’s New for Tools in JDK 9
# What’s New for Javadoc in JDK 9
What’s New for the JVM in JDK 9
- https://docs.oracle.com/javase/9/vm/compiler-control1.htm#JSJVM-GUID-94AD8194-786A-4F19-BFFF-278F8E237F3A
- https://www.voxxed.com/2016/11/java-9-series-segmented-code-cache/
- http://openjdk.java.net/jeps/276