sugarlife's blog

Javaとか、http://twitter.com/sugarlife

Java 14とJava 15の新機能解説 (LINE Developer Meetup #65 原稿)

Java 14とJava 15の新機能についてJJUG CCC 2020 Springで話す予定だった内容が中止になり、Java 15のリリースも近づいてきたので新たに資料を加筆修正して以下のLINE Developer Meetupで発表しました!

line.connpass.com

本イベントでは話す予定ではない部分も(JJUG CCCで話す予定だったので)資料にはあり、オンラインでの発表だったということもあり原稿も準備していました。そこで折角ですので情報保障を兼ねて共有したいと思います。情報保障についてはこちらを見てみてください。

なお、今回はかなり特殊な事例であり、基本的には原稿が公開されるケースは少ないと考えています。LINE Developer Meetupでは他の分野でもスライドに書かれていない内容を聞くことができるので、ぜひイベントを聴講してみてください :)

なお、スライドは以下から確認できます。また、スライドおよび原稿は元々markdownで記載しているため、はてな記法ではそのまま表示されています。

www.slideshare.net

ではお楽しみください:)

LINEでソフトウェアエンジニアとして働いている久保田祐史と言います。現在は全社的なKafkaのプラットフォームを提供しているチームで働いています。

(ここからは端折る)
これまでの仕事上、JVMトラブルシューティングに関わることが多かったため、過去にはOpenJDKやicedteaへのコードのコントリビューションだとか、JavaOneでのプレゼンテーションをしてきました。
またJava(JDK) Flight RecordのOSS化で役目をある程度果たしてしまいましたが、HeapStatsというJVMGCやクラス参照情報やヒープ情報の収集、そしてリアルタイムデッドロック検知等を行う、トラブルシューティングツールの開発も行っていました

私はよくJJUG CCCという国内のJavaのカンファレンスでGCJVMに関するセッションの他に、専らJavaの新機能について紹介することが多いのですが、今日も同じようにJava 14とJava 15で利用可能な新機能と変更点を紹介していきたいと思います。
新機能を中心に話すので非互換性については今回は話しません。


注意事項として、本資料は [`jdk.java.net`](http://jdk.java.net) からダウンロードできる`JDK 14.0.2` および`JDK 15 (build 32)`で極力動作確認していますが、全ての確認はできていませんのでコードを修正する前に動作確認してください
実装は各Javaのアップデートリポジトリ(http://hg.openjdk.java.net/jdk-updates/jdk14u/http://hg.openjdk.java.net/jdk-updates/jdk15u/)、そして最新リポジトリ(http://hg.openjdk.java.net/jdk/jdk)で確認しています


さて、それでは見ていきましょう。
Java 14と15ではこのような数だけ変更がありました。
Java Enhancement Proposals、JEPは新機能レベルの変更、Compatibility and Specification Reviewsは非互換性を伴う変更です。
これ以外にバグ修正も行われていますが、基本的にバージョンアップ時でしか行われない変更はこの2つです。
ただし最近はバックポートという形で新機能レベルの追加がマイナーバージョンアップデートで行われることがあります。つい先日JDK Flight RecorderがJava 8に導入されたのもバックポートの一つです。
いずれにせよバージョンアップデートが半年ごとになりましたが、アップデートの数は今でもあまり変わらず多い状態です。

先程言いました通り、今回は新機能について話しますので、ここでは追加されたJEPを紹介していきます。


まずはじめに言語レベルやAPIレベルの変更について紹介していきます。Java 14も15もこの変更が最も多数を占めています。


ここからは新機能を一つずつ説明していきます。

パターンマッチングがJava 14からプレビュー機能として導入されました。なおここで言う「パターンマッチ」は正規表現のではなく、オブジェクトの型、つまりクラスです。
今まではBeforeで示されている通り `instanceOf` で型を比較してからわざわざキャストする必要がありましたが、今後はAfterで示されている通りキャストする必要なくそのままダイレクトに処理を書くことができます。意外に細かい修正ですが、これによってコードがスッキリすることで読みやすさやメンテナンスのしやすさが想像以上に改善されました。
将来的には switch 文でも同じように記載できるようにすることが展望としてありますが、現在のところはドラフト状態でまだ時期も内容も定まっていません。

Java 15では変更なしでSecond Previewとなっています。通例的には大きな問題がなければ次のJava 16で標準機能となる予定です。

(注意)上のスライドの下部コードは「どのようなフィールドやメソッドが生えるか」のイメージ図を記載していたため明記していませんでしたが、クラス宣言は以下のようにするのがより正確です。

public final class TestRecord(String s, int i) extends java.lang.Record {

(注意ここまで)

Java言語仕様において長らくの問題(課題)であった「データを表したいだけなのに、書く必要があるコード量が多すぎる」に対する解決策として、レコード型がサポートされました。基本的な使い方は型の名前とそこに含めるメンバを宣言するだけです。通常のクラスの宣言と異なるのは、`class`の代わりに`record`と宣言すること、型名のあとに引数を宣言する必要があることだけです。この引数が扱う「データ」となります。

具体的に言うと上のコードを記載すると下のようなコードに書かれているフィールドやメソッドが自動的に生成されるイメージです。書かれている通りに順番に言うと、

  • 値は書き換えられない。つまりデータを表すフィールドは final になる。
  • 値の取得はgetter経由で行う。このgetterは変数名と同じになる。getHogeは作成できない(されない)。
  • 入力値に対する処理を行うことも可能です。
    • どういうことかというと、レコード型をインスタンス化するときは、(実質クラスであるので)クラスと同じようにコンストラクタが呼び出されるため、このコンストラクタ内で入力値のチェックや変換・加工などの処理を行うことが可能です。
    • 今回のコードの例ではコンストラクタを書いてないので、入力値がそのままフィールドに格納される基本的なコンストラクタが生成されています。
  • インタフェースを実装できます、ただし継承(拡張)は不可能です。なぜならすでにjava.lang.Recordをextendsしているからです。
  • 何度か触れてますが、新しいクラスじゃない「型」が導入されたように見えますが、バイトコードを覗くと実態は`java.lang.Record`を拡張したクラスであることが分かります。このクラスでtoStringなどのコメントアウトしている3つのメソッドが抽象メソッドとして宣言されているので、これらのメソッドがコンパイル時に自動的に生成されます。

Java 15ではこの基本的な使い方は変更されていませんが、一般的なクラスにおけるローカルクラスに対するローカルレコードという機能の追加などの変更が組み込まれています。
どういうことかというと、レコードを扱いたいアプリケーションとして考えられるパターンとして、あるクラスの中に単純な変数を複数持つ内部の値を扱うことが考えられます。現在は、こういった内部の値をヘルパークラスで扱っている実装が多いと考えられますが、これをレコードタイプとして扱えるようにする、というモチベーションです。
これ以外に後ほど説明するSealedクラスなどの対応も行われています。今後も変わる可能性があるので、実装について興味がある方は最新javacでコンパイルした結果をjavapでバイトコードを確認して確認することをお勧めします。


Java 13から導入されたテキストブロックがセカンドプレビューになりました。変更点は改行と空白を示す2つのエスケープ文字が導入されただけです。
具体的な使い方は表示されているとおりです。例えばやたら長い長文を記述したい時でもコード上ではみやすさのために改行を加えたいだとか、文末に空白を明確に記述したいときだとかに使うことができます。

この機能はJava 15で標準機能として昇格しました。


Javaアプリケーションで利用するメモリはGCによってJavaヒープ上で管理されます。しかしながら、アプリケーションによってはJavaヒープ外のメモリにアクセスしたいケースもあります。
これまではByteBufferの`allocateDirect`メソッドを利用する方法や、JNI(_Java Native Interface_)を利用する方法がありました。ほかに非公式ですが、`sun.misc.Unsafe.allocateMemory()`を利用する方法もあります。
しかし、これらの方法にはいくつか問題があります。
ByteBufferは1オブジェクトの上限がInteger.MAX_VALUE(2G)に限定され、全体で`-XX:MaxDirectMemorySize`で指定した値以下にする必要がありますが、メモリ割り当て解放のタイミングはGCに委ねられているため、意図せず超えてしまう問題がありました。
また、JNI(_Java Native Interface_)はC言語などでコードを書く必要があり、メモリ管理をすべて自分で行う必要があります。
そして、`sun.misc.Unsafe`クラスは非公式であるため将来的に無警告で削除される可能性があるうえ、名前のとおりに容易にJVMをクラッシュさせる安全でない操作を引き起こすことができるという問題を抱えています。管理してないメモリをいきなり触るとか。

このため、Java 14からはJavaヒープ外のメモリを扱うためのJava APIが新たに導入されました。JEPのページでは、メモリへの逆参照を行うサンプルとしてこのようなコードが示されています。

なお、このAPIはIncubatoorと書かれていますが、これは今後APIが削除されたり変更される可能性があるAPIを指し、標準モジュールとは異なる特別なモジュールで提供されています。本来は非互換性を極力廃するように変更が行われますが、これらのAPIはその対象外です。このAPIを利用する場合は`--add-modules jdk.incubator.foreign`を指定する必要があります。

また、このAPIはかなり広範囲がサポートされており、次のバージョンではAPIの利用方法が変わる可能性があります。Java 15でもmapped memory segmentのサポートが拡張されるなど、多数のAPIのリフレッシュが行われています。興味がある方はぜひAPIドキュメントを参照しながら使ってみてOpenJDKコミュニティにフィードバックしてください。あなたの貢献により良くなる可能性があります。Records以上に変わる可能性があるので常に最新APIをドキュメントから確認するようにしてください。


ここから Java 15 で追加された機能です。Java 15では新たに二種類のクラスが追加されました。この内の一つがシールドクラスです。

これは誰がサブタイプになれるかを完全に制限することが可能なクラスです。これによって今までのアクセス修飾子よりも、クラスやインターフェースの作者が、より明示的にどのコードが実装を担うかを宣言することができるようになりました。副次的な効果として、サブクラスを完全にコントロールすることができるので、パターンマッチングもより網羅的に行うこともできるようになります。

通常のクラス宣言と違うのはclassの前にsealedと宣言すること、そして継承や拡張を許可するサブタイプを`permits`宣言のあとに記載します。今回はパッケージ名も含めてFQDNで記載していますが、同一パッケージであればクラス名だけで指定することも可能です。

特徴としては、封印された型の匿名のサブクラス(およびラムダ)は禁止されています。また、特に指定がない限り、sealedのabstract、つまり抽象的なサブタイプはsealedとなり、通常のサブタイプはfinalとなります。各サブタイプの宣言時に`non-sealed`と明示的に指定することでこの制約は回避することができます。


もう一つはHidden Classesと呼ばれるクラスです。このクラスは限定された方法以外では他のクラスやインターフェースからはアクセスできない、他のクラスから完全に秘匿されることを目的としています。
完全に秘匿するということはどういうことでしょうか?実は今までの実装ではリフレクションを利用するなどで無理矢理読もうと思えば読むことができるのです。

現在の実装はあるクラスのバイトコードコンパイル時に作成されたもの(静的クラス)か、ランタイム時に作成されたもの(動的クラス)かを区別しません。なお、コンパイル時に作成したものを静的クラス、ランタイム時に作成したものを動的クラスと言います。このため、ある動的クラスが同じクラスローダー階層にいる別のクラスから名前を元にリンクしようとする度に可視化されてしまうため、完全な秘匿を実現する方法がありませんでした。これによって、動的クラスのライフサイクルがリンクしている静的クラスが開放されるまで保持され続けるなど、想定以上に長くなってしまう問題がありました。

これを回避するために、フレームワークにより実行時に生成され、他のクラスから秘匿されつつリフレクションを介して間接的に使用でき、他のクラスから独立してアンロードできることを目的としたのがHidden Classesです。

通常のクラス、またはインターフェースは`ClassLoader::defineClass`を呼び出すことで作成されますが、隠しクラス、インターフェースはMethodHandles.Lookup#defineHiddenClassを呼び出すことで作成されます。このメソッドはbyte配列から隠されたクラスを生成し、reflective accessをもつlookupオブジェクトを返します。このlookupオブジェクトが隠しクラスのClassオブジェクトを取得する唯一の方法となり、他の方法からはアクセスできないようにすることで、完全な秘匿を達成しています。


このほか、細かい変更としては次のようなものがあります。

まず1つは、LegacyなSocket APIの再実装がJava 13で行われました。これに基づき、周辺APIの再実装を進めようという内容です。この実装はJava 1.0から導入されており、C言語Java言語が共存している状態でメンテナンス性が損なわれていました。他、非同期クローズなどの並行処理で難があったのでそういった部分の改善が行われる予定です。

ByteBuffer APIが不揮発性メモリにも対応しました。

`java.rmi.activation`パッケージに属するクラスやインターフェース及び関連クラスが非推奨化され、`rmid`ツールが非推奨化に伴い警告が出るようになりました。

つづいてJVMの挙動に関する変更について紹介していきます。この変更は大きなものが2つあります


(きしださんが説明するので21までSkip。以下は元ある原稿)

本来はnullを想定していない処理中にJavaアプリケーションがnullを受け取ってしまった際に、`NullPointerException`が発生します。
Javaのコードを書いたことがある人にとっては、NPEは珍しくないと思いますが、念のために説明すると、NPEの基本的な対処方法は、スタックトレースから例外が発生したコードの行を確認し、どのオブジェクトがnullとなったかを推定することでコードの修正を行うことが挙げられます。
例えば次のようにSampleクラスを実行した結果、NPEが発生したスタックトレースを受け取った場合は、Sample.javaの4行目に`null`となったオブジェクトがあったと判断することができます。


もしこのSample.javaの4行目が次のようなコードだった場合、Nullとなっている可能性があるオブジェクトは`person`か`person`が持つ`name`の二箇所であり、比較的範囲が絞られているため対処も簡単です。
今回に関して言えば8行目でnameにnullを入れているので明らかにこれが原因です。

しかし次のコードのように、オブジェクトを多数利用している場合はどこでnullになったのか一見では解らないぐらいに被疑箇所が多く、かつそれぞれのオブジェクトがまったく別の処理で作成していた場合では、調査に時間を要することも珍しくありませんでした。
現実的には三次元配列はめったに使わないし、オブジェクトがNullableかそうでないかは考慮したうえで実装しますが、世の中思わぬところでnullになって調査が難航することは稀に良くあります。

このため、Java 14からはこのオプションを設定することで、具体的にどの処理を行った際にどのオブジェクトがnullだったかを表示するように変更が行われました。
このオプションを付けて先程のSampleクラスを改めて実行してみましょう。

ちょっと見にくいのでエラーメッセージを改行してみます。今後出るエラーメッセージも必要に応じて改行しています。

このように、どのような処理中にどのオブジェクトがnullであったかを完璧に表示しています。これによって先程のようなメソッドでもどこがnullであったかを知ることができます

nullを表示するエラーメッセージは処理やnullの箇所に応じて出力内容が変わります。特にローカル変数についてはひと手間必要なので追加で紹介します。
次のようなローカル変数`names`がnullになっていたケースを見てみましょう

実際に実行してみるとObject配列を読み込もうとした際に(When)ローカル変数(What)がnullであったため読み込めなかったことを示しています。実際のローカル変数名はここに書かれている内容(`local1`を指す)ではありませんが、通常のコンパイル方法ではローカル変数情報が含まれていないためこのような表示のされ方をします。

ローカル変数の名前を明確に表示したい場合はローカル変数を含むデバッグ情報が必要なため、次のようにクラスファイルをコンパイルする際に`-g`オプションを指定する必要があります。

`local1`ではなくローカル変数の名前が`names`と明確に出力されるようになりました。

この出力は非常に便利ですが、ローカル変数のデバッグ情報が増えるため、クラスファイルのサイズが増大するため配布時に影響が出る、クラスロードを行う時間が多少延びる、そしてリバースエンジニアリングのヒントが増えて行いやすくなるという問題もあります。このため、このオプションは基本的には開発環境で利用することをお勧めします。

この機能全体の懸念点としてパフォーマンスへの影響が挙げられますが、NPE発生時、正確にはスタックトレースの生成時にメッセージを取得するようにしているため、特筆すべきレベルの大きな影響はありません。頻繁にNPEを発生させているアプリケーションの場合は性能に影響がある可能性もありますが、そのようなアプリケーションはそもそも処理の見直しを行ってからパフォーマンスを確認してください。

Biased Lockingがデフォルトで無効化されました。

このBiased lockingはuncontented lockingのオーバヘッドを下げるためにHotSpot VMにかなり早い時期に導入されました(当時はOSSじゃないので伝聞です)。
これは、あるthreadがmonitorを取得しようとするまでモニタは特定のスレッドに所有されたままであると仮定することでatomic操作回数を減らし、多くのスレッドがシングルスレッド方式で使用しているオブジェクトに対する同期操作(を多く行っているケースで)の性能改善を図っていました。

初期のAPI(java.util.Vectorなど)はアクセスの度に同期をとる実装になっており、非同期コレクションはJava 1.2から、マルチスレッドを考慮したAPIJava 5からと導入が遅めだったため、初期は実際に目覚ましい効果がありましたが、並列処理用のAPIが充実してきた昨今では逆に性能が悪化している(ベンチマークツール、SPECjbbより判明)状況でした。

また、Biased lockingによってJVMのコードもメンテナンスしづらくなっているので非推奨化して最終的には削除する方針となり、Java 15からはデフォルトで無効になりました。

  • XX:-UseBiasedLockingで以前のJavaでも無効化することは可能です。逆に有効にしたい場合は-を+に変更することで可能ですが、将来的には削除されるので無効化するのが望ましいでしょう。


(練習通りいくと時間が足りないので、GCについてはまとめてこのスライドで説明する。27までskip、以下は元ある原稿)

続いてGC関係について説明していきます。Java 14では細々とした変更が入り、Java 15では試験的なGCが標準機能となりました。

Java 15で導入された2つのGCを軽く説明すると、ZGCはテラバイト級までの巨大なヒープを扱いながら、アプリケーション停止時間を10ミリ秒以下にすることを目的としたGCで、Shenandoah GCはG1 GCのようにリージョン単位でヒープを管理しつつ並列コンパクションを採用したGCです。


NUMAとは複数のプロセッサが共有しているメモリへのアクセスコストを、プロセッサとメモリ領域ごとに偏りを持たせたアーキテクチャです。
しかし、JavaGCによってメモリ管理が行われているため、未対応であったG1 GCを利用している場合は、この偏りを無視してメモリを利用する可能性がありました。
現在のデフォルトであるG1 GCは、NUMAノードを意識してヒープリージョンの配置を行うように改善が行われました。
これにより、NUMAアーキテクチャを採用しているサーバ上でG1 GCを利用してJavaアプリケーションを運用している場合、パフォーマンスの改善が見込まれます。


非推奨であったCMS GCが完全に削除されました。
ただし、オプションを指定して実行すると、このような警告が出てデフォルトのGC、今だとG1 GCが選択されて実行されます。poorな環境だとSerial GCが選択されます。
起動失敗しないのでCMSのつもりでG1で動いてて「アプリケーションの動作がおかしい!」とか「ログ内容がおかしい!」とならないように注意しましょう。

いずれにしてもGCアルゴリズムはちゃんと明確に指定しましょう。


Java 11から試験機能として導入された、テラバイト級までの巨大なヒープを扱いながら、アプリケーション停止時間を10ミリ秒以下にすることを目的としたZGCはLinuxのみだったが、macOSおよびWindowsでも利用できるようなりました。

ZGCは弊社のHBaseチームが検証して記事を出してますので興味ある方はそちらを確認してみてください。


次のようなオプションでYoung GCをパラレルで、Old GCをシリアルでGCを実行する組み合わせが非推奨になった

(補足)
一般的に、システムリソースを気にするならYoung GCのほうが実行回数が多いので、こちらをシリアルにしてOld GCも合わせてシリアル、または回数が少ないのでパラレルにするのは合理的だが、逆にするシチュエーションはあまりないのでメンテナンス性を考慮して将来的に削除される予定となった。

最後にツールの変更です。これはJava 14の変更のみです。

(補足)
ただし、JEPにはなっていませんがJava 15でも`rmic`が削除されたりはされています


パッケージングツールです、平たく言うと各OSに合わせたインストーラーを作成するためのツールです。
Windowsだけは外部のWiXツールを追加でインストールする必要があります。
このツールはincubatorなAPIに依存しているため、incubatorと記載されています。
今後のJavaアプリケーションを提供する流れとしては、カスタムランタイムイメージをjlinkで作成し、その後インストーラをこのツールで作ってユーザに提供する、と想定されています。


`--input`でjarファイルが置かれているディレクトリを指定し、メインJARファイル、メインクラスをそれぞれ指定して実行します。すると、macOSであればsample-1.0.dmgなど、OSに合わせたインストーラが作成されます。

カスタムイメージでの作り方は依存しているモジュールを表示する。モジュールを指定してjlinkでカスタムイメージを作成する。

そしてこのツールで`jlink`で作ったカスタムイメージを`--runtime-image`で指定しているだけです。この方法を利用するメリットはインストールされるサイズが抑えられることと、インストーラそのもののファイルサイズも抑えられるところです。

JavaはRun anywhereを掲げておりJARファイルの提供だけで済むのが言語のメリットの一つではありますが、Javaの実行バイナリがより多くのベンダや団体から提供されるようになったので、このようなインストーラでバイナリごとインストールさせるメリットが以前より大きくなったと捉えることができます。


(いとうさんが説明するので37までskip、以下は元ある原稿)

HeapStatsの商売敵というか元々プロプライエタリであったOracle社製トラブルシューティングツールであるJava Flight RecordがJava 11からOSS化され、つい最近例外中の例外的にJava 8にもバックポートが行われました。

Javaは商標なのでJDK Flight Recorderという名前になりました。

このJDK Flight Recorderにストリーミング機能が新しく追加されました。これまではJFRで取得した情報はダンプしたファイル経由で読み取る必要があり、リアルタイムでのモニタリングが行いにくいという問題がありました。

この新機能により`RecordingStream`クラスを通じて、リポジトリを経由して別のJavaプロセスから継続的に取得したり、もちろん同じJavaプロセス内でも取得したりすることが可能になりました。

まずは次のJFRSampleクラスのように、JFRをローカルで開始して記録を行い、ストリームを作成して継続的に標準出力してみましょう。このクラスを実行すると、CPU負荷イベントを10秒ごとに出力します。


CPU負荷イベントの情報はこんな感じで出力されます。


単純に定期的に出力するには分かりやすい値だったためCPU情報を収集していますが、他にデフォルトで用意されているイベントを収集することができます。用意されているイベントはJDK内のhttps://hg.openjdk.java.net/jdk/jdk14/file/e568ce785bdf/src/hotspot/share/jfr/metadata/metadata.xmlに定義されています。

ThreadStartやThreadPark、JavaMonitorなどのスレッド情報から、ClassLoadなどのクラスローディング情報、ヒープ使用量や各GCアルゴリズムごとの統計情報など多種多様なイベントを出力できます。
これ以外にもJFR APIを利用して、具体的にはjdk.jfr.Event(https://docs.oracle.com/en/java/javase/14/docs/api/jdk.jfr/jdk/jfr/Event.html)クラスを拡張することで、自分で独自にイベントを作ることも可能です。この機能は今回導入された機能ではなく、Java 9から提供されています。

また、JFRはどういったイベントを有効にするかの情報が設定されている基本構成としてdefaultとprofileの設定が用意されており、この構成を利用してストリームを作成することも可能です。記録するイベントの設定漏れを防げるなどの理由から、基本はこちらのほうがお勧めです。
なお、profile構成を利用した場合は出力される情報量が多いため、それなりにJavaアプリケーションにオーバーヘッドが掛かるので注意してください。いきなりプロダクションで有効にするのではなく、性能がどれだけ落ちるか確認したほうが良いでしょう。


ローカルJavaプロセスの情報であればなにもJFRを利用する必要はありません。あるJavaプロセスで収集しているCPU負荷イベント情報を、別のJavaプロセスから取得してみましょう。そのためにはまずは、対象JavaプロセスのJFRリポジトリパスを`jcmd`から確認します。

このリポジトリパスはデフォルトではOSのテンポラリディレクトリですが、Javaの起動時にこのオプションを使って指定することもできます。


このリポジトリパスへのストリームをJFRRemoteSampleのように開くことで、別のJavaプロセスから監視を行うことができます。せっかくなのでメソッドプロファイリングを行うイベントを標準出力しました。


このように別のJavaプロセスからもリポジトリを参照することで、リアルタイムに情報の収集が行えます。
なお対象のJavaプロセスを終了するとストリームが終了するため、自動的に収集も終了します。また、対象Javaプロセスで記録していない情報以外は当然ながら収集することはできません。

これまではファイルをダンプして事後解析が必要でしたがこれによりだいぶ楽になりました。リポジトリを見れば最大でも1秒以内というほぼリアルタイムで時系列データを得ることができ、事後解析も楽にすばやく取りかかることができると期待できます。


注意事項として、JFRは様々な情報が収集できるため多角的な解析手段としては最高峰ですが、OOMEやクラッシュ時のメモリ情報収集は苦手であるということに注意してください。
Leak Profilerの実装的な問題により、長期的なメモリリークであれば収集できる可能性は十二分にあるが、超短期間のメモリ使用量上昇、ようは瞬間的なスパイクによるOOMEであればオブジェクトサンプリングが取得できない可能性があります。
このため、JFRとは別に`HeapDumpOnOutOfMemoryError`オプションでプロセスが死亡する際にヒープダンプを取得する必要があります。


この他、細々とした変更点として、新しい暗号署名が追加されました。
Java 8で導入され、Java 11で非推奨化されたJavaScriptエンジンであるNashornとjjsツールが削除されました。
そしてSplarisとSPARCポートが削除されました。


以上です、ご清聴ありがとうございました

ボードゲームを普段遊ばない人と楽しみたい

ボドゲはいいぞ。この記事はpyspa Advent Calendar 2019の18日目です。

ボードゲームを普段遊ばない人をすっと沼に沈めてボードゲームで遊べる友人を増やしていきたい。

ボードゲームのとっつきやすさを決める要素は、個人的にはおおざっぱに次のようになると考えている。

  • 複雑さ
    • ルールの複雑さ。あるいは最初のルール説明(「インスト」とよく呼ばれる)の長さ。ルールを説明されてすぐ何をすべきか分かるかどうか。
  • 難しさ
    • 勝利するために必要な手を考えるむずかしさ。複雑さが原因になりやすいが、それ以外にも選択肢の多さや操作すべき要素の量が難しさにつながる。
  • 時間
    • プレイ時間。「軽量」ゲームと呼ばれるものはプレイ時間が短い。逆に複雑さ・難しさが高いと一人あたりの時間が伸び、結果としてプレイ時間も伸び、「重量」ゲームと呼ばれる。
  • 人数
    • 重量系は4人用が比較的多い。

これを踏まえて、4-6人用を目途に普段遊ばない人を誘いやすい「とっつきやすさ」に振り切ったボードゲームをリストアップしてみた。

反射神経系ゲーム

目の前にある情報を元に素早く対応した人が勝ちなゲーム。いわゆる早押し。
1-2回試しにやってみれば即ルールが分かるのでとてもとっつきやすい。子供の方が強いケースもある。
ただし、反射神経が物を言うゲームなので強い人がめっぽう強い。そういった場合は酔いを入れてカオスを持ち込みましょう。

お化けキャッチ

5種類のコマを中央に置き、カードをめくってそこに書かれていない「色」と「形」のコマ、あるいは「色」と「形」が完全に一致しているコマを一番早く取った人が勝ち。
ルールが二種類あるので分かったつもりでも間違えることがあり、飽きにくく面白い。勢いよくコマを取っても多少の事では壊れないので子供にもおすすめ。

Dobble

それぞれのカードに8種類の絵が描かれている。中央に置かれたカードと自分のカードに共通している絵が必ず一つだけあるので、それをコールして早く取るゲーム。
強い人が割と本当に強いゲームなので一方的になりやすいことがままある。

積み木系ゲーム

ジェンガのようにモノを手に取って操作することで決着をつけるゲーム。モノの制約上、ルールがシンプルなのでとっつきやすい。問題は「ボドゲか?」という点と持ち運びが不便な点。あまり気にしないで進める。

スピードカップス

カードに書かれている通りに、手元にあるコップの色と並べ方を揃えてベルを鳴らせば勝ち。
反射神経系でもあるが、モノが絡むと意外に時間が懸かったりする。

バンボレオ

不安定な台の上に様々なブロックが置かれており、崩さずにとっていき最後に崩した人が負け。シンプルかつ強い人は定まりにくいので盛り上がりやすい。
ただし高い。

連想ゲーム

コトバーテル

五文字の言葉を敵チームと交換し、カタカナ一文字を表すカードを山札から引いて味方に伝えるゲーム。
ルールはシンプルだが人によって伝え方が意外に癖があるので、少しずつ伝えようとしている言葉が分かるにつれ盛り上がりやすい。

ディクシット

様々な場面やキャラクタといった絵が懸かれたカードをそれぞれ配り、親が絵から連想できる言葉を良い、親と子はそれぞれその言葉を表しそうなカードを伏せて場に出す。その中から親が出したであろうカードを一斉に選ぶ。親は全員当たりか外れだと点数なし。このため、当たりそうで当たらない微妙な連想が問われる。それぞれの発想が問われるので意外な展開になりやすくて盛り上がりやすい。
が、独創的すぎる人が入ると色んな意味でバランスが崩壊しやすい。それもまた面白い。

バカゲー

ちょっとだんしー

ソクラテスラ

名前が三枚に分割されている偉人カードを並べて新しい名前を作り上げるゲーム。
なお、偉人にはチン ギス ハンとナイ チン ゲールとラス プー チンが含まれている。
続編には「のお母さん」というカードもあるぞ!

まとめ

このようなとっつきやすさ至上のゲームで誘い、「タイムボム」や「二ムト」のようなカードゲームを経て、「カルカソンヌ」と言ったもう少しボドゲらしいゲームに移行し、最終的には「テラフォーミングマーズ」や「サイス」といったボドゲに引きずり込んでいきましょう!

最近のProject Jigsaw の流れ:コミュニティ投票でNo (Public Review Ballot)

Java の新たなバージョンである JDK 9 のリリースが約 2 ヶ月後に控えているが、最大の目玉と言っても過言はない Project Jigsaw がコミュニティから No を突きつけられた。この最近の流れを、極力意見を混ぜずに事実を淡々と紹介する。

Project Jigsaw とは

  • 乱暴に言うと Java の新しい分割の仕方としてモジュールを導入しようという取組
  • 詳細は手前味噌ですが以下のスライド参考

前提

最近の流れ

Project Jigsaw は Draft Releases の期間でした。なお、私は OpenJDK 実装をそれなりに読んでおり、各自の立場から反対意見の要約を示すことができないと思いますので、詳細な内容は紹介しません。詳しくはリンク先を確認してみて下さい。

2017/1/17 - 2/16 Early Draft Review
  • Spec Lead (Oracle の Mark Reinhold氏) (と Expert Group) により JSR の要件に則った仕様書の草案が公開され、(場合によっては大幅な)レビュー&改訂作業が行われる。ここでは一般のレビューは行われません。
    • Spec Lead の Mark 氏は JDK 9 全体の Spec Lead も兼任している
3/21 - 4/20 Public Review
4/25 - 5/8 Public Review Ballot

f:id:cco:20170509194940p:plain

これからどうなるか

JCP で定められている通り、否決された場合は Spec Lead と Expert Group は 30 日以内に EC から提起された懸念に対応するための仕様草案の更新・修正を行い、再び審査投票を実施します。この審査投票でも否決された場合は JSR は終了し、Expert Group は解散されます。

ただ、JDK 9 のリリース予定日が 7/27 と差し迫っている中、懸念に対する仕様変更はまだしも、その実装は更に時間がかかる可能性が高く、リリースにも影響が及ぶことは十分に考えられる状況です。現在はまだ投票結果が出たばかりなので、今後の動向に注目していく必要があります。

追記

追記1:Jigsaw 否決の内情について

EC member は全団体が頭ごなしに No と表明しているわけではありません。その一例として Tomitribe のコメントを紹介します。

Though a No vote feels like rejection we ultimately believe it is the most supportive vote for gaining a greater level of consensus we believe is necessary from a JSR, while still keeping time pressure.

Jigsaw における技術的な課題について指摘している団体もおりますが、懸念について駆け込み的に対応しようとした Expert Group とのコンセンサスの取り方について疑問を持ち、最初の投票で Yes と投じにくいと判断した団体も多くいるようです。各団体のコメントは投票結果のページから確認ができます。

追記2: JDK 9 の JSR

JDK 9 も同じタイミングで JSR 379 Java SE 9 Release Contents にて JCP の承認プロセスを実施していますが、こっちは賛成多数で可決しました。

f:id:cco:20170509203914p:plain

jcmd と既存ツールの対応

はじめに

この記事はJava Advent Calendar 2016の 1 日目の記事です

先日の Java Casual #2) で jcmd について話してきました。

jcmd は Oracle 社のドキュメントでは推奨ツールとして扱われており、jps や jmap, jstat のような既存ツールは "Experimental" とされています。このため、既存ツールから jcmd への移行が進められる可能性があります。例えば Experimental であった jhat は Java 9 から削除されます。

Java 9 からの新機能を含めた jcmd の各種機能は上記スライドを見ていただくとして、ここでは jcmd でどのように既存ツール相当の機能が使えるかを紹介したいと思います

続きを読む

OpenJDK のリポジトリから特定バージョンの Java のソースコードを落とす方法

例:JDK8u77 のソースコードを落としたい

解説
  • OpenJDK のソースはタグ管理されているので、JDK8 Updates Master のタグ一覧を確認する
  • u77 の最新の b 番号は b03 なので jdk8u77-b03 が取得したいソースコード
  • これを mercurial コマンドと OpenJDK のツールから持ってくる
  • jdk8 以外は jdk8u の部分を適当に入れ替える。(※ただし動作確認してません)

G1 GC おさらいと #jjug_ccc で発表した話

この記事は Java Advent Calendar 2015 の一日目の記事です。二年連続でトップバッターだ!

先日の JJUG CCC 2015 Fall で G1 GC について話してきました。
去年の CMS GC と同じく結構遅めの時間帯&裏番組に伝説の灰色ページ管理人・ひしだま伝道師が発表するなどの豪華な時間帯にも関わらず、165人規模の部屋がいっぱいに埋まるぐらいの盛況でした。聴講頂いた皆様ありがとうございました!
スライドは以下に公開しました。G1 GC の挙動から GC ログの読み方、どういうケースが厄介なのかを紹介しているので是非ご覧ください!

アフターフォロー、またはちょっとした補足

極力、後から参照可能なように資料を作っていますが、どうしても口頭で補っている部分はあります。
セッションのハッシュタグである #ccc_cd6 で Twitter 検索した結果 なども合わせてご確認ください。

一般的な注意事項について
  • JDK9 から G1GC がデフォルト化されます。JDK9 を導入される際は使用する GC を明示的に指定することをお勧めします。
  • ヒープサイズが小さい環境で G1 GC を選択する際は注意してください。元々ヒープサイズが巨大な環境のために開発されたものなので、ヒープの使用「率」(-XX:InitiatingHeapOccupancyPercent) が比較的低い段階から活発に GC が実行されるなど、本来のメリットがデメリットとして襲い掛かってくることがあります
オプションについて
  • CMS GC と同様に -Xmx と -Xms は同じ値にしたほうが、拡張/シュリンク時のコストが発生しないのでお勧めです。
  • オプションで Young 領域(Eden、Survivor 空間)のサイズは指定しないほうが性能が良いケースがあります。これは Young 領域のサイズを設定しない場合は状況に応じて JVM が動的に変更するため、人間が決め打ちでやるより効率が良くなるパターンが往々にしてあるからです。
  • -XX:MaxGCPauseMillis は STW の時間を指定するものではありません(主にマーキングサイクルのコンカレント部分に効く)
検索して引っかかる古い情報について
  • 以下のスライドの Mixed GC の処理条件が最近のアップデート(JDK-8059452, JDK8 update 40)で、緩めなOld 領域をより徹底的に回収する条件に変更されてます。JDK9 でデフォルト化の話がこの辺りで出てきたので、それに前もって導入された印象です。
    • G1MixedGCLiveThreshold が 65 から 85 に変更
    • G1HeapWastePercent が 10 から 5 に変更
    • 追記 2015/12/1 12:40 @den2sn さんよりコメント頂き表現を修正。合わせてスライドも表現が誤っていたので修正。

  • 以下のスライドの Evacuation Failure が発生した際、次のページに書かれてるようにログに (to-space exhausted) という文字列が出力されます。しかし、 Oracle のドキュメント等によると (to-space overflow) と出力されるバージョンもあるようです。今回の発表スライド作成時に確認したソースコードにはそういう文字列はありませんでした。古いバージョンを利用する場合はこの文字列も注意してください。

伝えたかったこと

これまで 渋谷Java で OutOfMemoryError の話をきっかけに、JJUG CCC 2014 Fall で CMS GCJava 女子部で JVM のいろは、そして今回の G1 GC の話をしてきました。これらの発表の原動力は去年の夏の JJUG ナイトセミナー LT 大会でした「楽して JVM を学びたい」という発表が大元です。

勉強するためには、体系だった知識が下敷きにあるとないとで理解の差が段違いです。特に自分は難聴者なので、分かりやすい資料や書籍があるかが大きな差となりました。なるべく JVM の勉強をしてみたいという人に向けて、特に問題になりがちなメモリ管理の分野に関して、実際のトラブルで役に立つ知識を中心に、後から読み返してもスッと入ってこれる体系だった丁寧な資料作りを心がけてきました。

これまで OpenJDK のソースコードを読み、数々のそれなりにタフなトラブルシュートを駆け抜け、たまに OpenJDK パッチを書いて投稿しという活動を繰り返してきました。いまだにコミッターどころか Author にもなれてませんが、自分なりに Java のコミュニティに貢献できればと思い発表してきました。どこかの誰かの「楽して JVM を学びたい」という気持ちに答えられていたら幸いです

www.slideshare.net

www.slideshare.net
www.slideshare.net
www.slideshare.net
www.slideshare.net

おまけ

最終回っぽい〆をしてますが、別に Java はやめません :p

JDK9 新機能ダイジェスト (JDK9 Features) #java

JJUG ナイト・セミナー 「ビール片手にLT&納涼会」で、来年出る予定のJDK9の新機能(2015/7/31時点)について喋ってきました。JDK9の機能が全て出揃う(Feature Complete)のは 2015/12/10 ですが、これから大量に出てくるのも考えにくいので LT の時点で出ている分をまとめました。

JDK8 で導入された機能についても過去にまとめてあります

新たな JDK で導入される機能について

Java 関連の周辺技術標準化は JCP(Java Community Process) によって行われ、新しい技術仕様や改訂仕様(既存技術仕様の改訂)は JSR (Java Specification Request) として提案され、標準化に関する作業が管理されます。
では、JSR を追って行けば JDK の新機能が解るのか?実はそれは違っていて、JDK で何かしらの新機能を加える場合、その内容は JEP (JDK Enhancement-Proposal) として管理されています。JDK 9 の機能部分は、Oracle 社独自の変更(解りやすい例としてFlight Recorder周り)以外の変更点は、OpenJDK 9 プロジェクトの Features から確認できます。今回はこの JEP についてダイジェストをまとめてみました。

発表資料

以下、JDK9 新機能のダイジェストです、ご査収ください

以下の英語版はもうちょっとだけ詳しく書いてます

LT 時は五分でおさまるように練習したのに、遅刻気味で全力疾走からの飲酒を決めて酔っ払い、5分で喋りきれませんでした。すみません(・ω<)てへぺろ

JDK9 の影響

それぞれで影響が大きい機能は異なってきますが、以下の機能は多くのプロダクトに影響が大きいかもしれません。

  • Project Jigsaw (JEP 220、他)
    • sun.* パッケージの扱い (JEP 193、他)
  • JVM ログ統一 (JEP 158)
  • G1GC デフォルト化 (JEP 248)

個人的には P.12 にまとめた sun.misc.Unsafe の動向が超重要(JDK内部でも使ってるし即消えることはないとは思いますが…)で、G1GC リプレース型の新 GC (Shenandoah) どこ行ったという所感です。