Oracle Developers Live Java 視聴ログ
Java 15 のリリースに合わせて開催されたオンラインイベントのセッション動画が公開されたので面白かったところのメモ。
- Java Language Futures—Mid 2020 Edition (35:32)
- ZGC: The Next Generation Low-Latency Garbage Collector (39:26)
- Keeping Your Java Applications Secure: Cryptographic Improvements and Best Practices (37:09)
- This Ain’t Your Parent’s Java (40:45)
- Project Loom: Modern Scalable Concurrency for the Java Platform (38:34)
- Collections Refueled (30:16)
Java Language Futures—Mid 2020 Edition (35:32)
JDK 15 で導入されたフィーチャーの紹介。
- Records (JEP384)
- ボイラープレートコードを省略すること自体は目的じゃない
- 他の言語でいうタプルのような存在
- Pattern matching for instanceof (JEP375)
- Sealed Classes (JEP360)
- 特筆することがない…
- Text Blocks (JEP379)
- 紹介されなかった
Java 15新機能まとめ - Qiitaを読めばいいことがわかった。
ZGC: The Next Generation Low-Latency Garbage Collector (39:26)
発音:ズィージーシー
- 参考リンク
今利用できる GC アルゴリズムと特徴
GC | Optimized for |
---|---|
Serial | Memory Footprint |
Parallel | Throughput |
G1 | Throughput/Latency Balance |
ZGC | Low Latency |
ZGC の特徴
- リージョンベースで並行処理
- NUMA対応でトレーシング可能
- ロードバリアによるコンパクション
- 単一世代で色ポインタを利用する
- ヤング・オールドみたいな世代はない
- 停止時間はヒープサイズやライブセットサイズに依存しない(ルートセットサイズに依存する)
- クラスアンロードもできる
ZGC の振る舞い
- マークスタートフェーズ
- 10ms 以下
- 対象オブジェクトにマークする
- マッピングを修正する
- マークエンドフェーズ
- 10ms 以下
- マークしたオブジェクトをリアロケートするための準備
- リアロケートフェーズ
- 10ms 以下
- 準備したオブジェクトをリアロケートする
色ポインタ
- オブジェクトポインタの構造
- 未使用ビットとオブジェクトアドレスの間の 4 bit をメタデータとして利用する
- マーク済み、とか、リアロケート対象、とか
p = 未使用 (16 bit) + 色ポインタ (4 bit) + オブジェクトアドレス(44 bit, 16 TB に相当する)
ロードバリア
- ヒープのオブジェクトを参照するときに JIT がコード片を挿入する
- ロードしたタイミングで色ポインタをチェックする
- チェックして問題があれば修復する
ZGC の性能
- SPECjbb2015 のベンチマークによると
ZGC の未来
- GC停止時間のさらなる削減 - 1 ms 以下にしたい
- GC停止時間がルートセットサイズに依存しないようにしたい
- 今のところスレッドスタック処理に未対応なため (JEP 376 で議論してる)
- 世代別 GC
- 従来アルゴリズムにあるようなヤング・オールド
- 検討中
Keeping Your Java Applications Secure: Cryptographic Improvements and Best Practices (37:09)
Cryptographic Improvements
- 安全なアルゴリズムの提供
- 安全でないアルゴリズムの使用を制限
- 関連する警告やイベントを出力するようになっている
keytool
やjarsigner
の出力に気を付けよう- JFR で観測できるイベントが増えている
jdk.SecurityPropertyModification
jdk.TLSHandshake
jdk.X509Validation
jdk.X509Certificate
Secure Programming Best Practices
Secure Coding Guidelines for Java SE の紹介。
コーディングガイドは10章構成。
- 1-3章は基礎
- DoS
- 機密情報の保護
- 注入攻撃
- 4-10章はコードと権限に関連する
Java に限定した話じゃないので注意が必要。
要するに、プロセスの外部から入力されるデータは信用できないので、言語機能を公開するべきではない、みたいな感じ。
自分でコーディングする場合以外に、フレームワークやソリューションを選定するときも注意したほうがいいと思う。
This Ain’t Your Parent’s Java (40:45)
個人的に心の中で Java 芸人と呼んでいるベンカット・サブラマニアンのマシンガントーク (貴重な Emacsen でもある)。
Project Loom: Modern Scalable Concurrency for the Java Platform (38:34)
並列性の目的はスループット
- スループットはリトルの法則
L=λW
に支配されている- λ - 並列度 (制御できる)
- W - 平均レイテンシ (外部サービスへのアクセスなど、制御できない部分が混在する)
- L - 並列性の度合
現在の Java スレッド
- OS スレッドのラッパー
- タスクスイッチにカーネルモードへの切り替えが伴う
- OS のスケジューリングに依存
- キャッシュの局所性が悪い
- スレッドごとの消費リソースが大きい
- スレッドプールを使えば再利用できるけど別の問題が生じる
- 結局のところ同期処理と非同期処理のトレードオフになる
- 人間にやさしい vs マシンにやさしい
- 簡単 vs 複雑
- いいとこどりしたい
- 前方互換性を保ちつつ( 既存の資産を守りつつ ) 新しい機能を導入したい
そこで Java スレッドの再設計
Thread.currentThead()
はあちこちで使われてるので注意が必要- Java 5 以降は
Executor
/Future
を利用するようになってるから直接的に Thread API を使う場面は減っている - Thread API を大掃除すればかなりフットプリントを削減できる
新しい Java スレッド = Virtual Threads
- スタックのサイズを可変にする
- メタデータに 2kB 使っていたのを 200-300B にする
- スタックに 1MB 使っていたのを可変にする
- ユーザーモードでコンテキストスイッチできるようにする
- 長くて 10μs から 200ns 以内に短縮する
- スケジューラーを交換可能にする
利用者にとってのメリット
構造化並列性という概念の導入
- 構造化とは ?
- ランタイムの振る舞いをコードに反映すること
- libdill(C)や Trio(Python) で採用されている
Executor API の改善
- 1
ThreadExecutor
は Auto-Closeable になり、すべてのタスクが完了するまで待機する- スレッドプールにタスクを submit する API は変わらない
- 2 指定した期間を経過したらタスクを実行してるスレッドを interrupt する
- 3 join や wait や cancel を簡単に扱えるようになるはず
コード例。
// 1 ThreadFactory factory = Thread.builder().virtual().factory(); try (var executor = Executors.newThreadFactory(factory)) { executor.submit(task1); executor.submit(task2); } // 2 ThreadFactory factory = Thread.builder().virtual().factory(); try (var executor = Executors.newThreadFactory(factory) .withDeadline(Instant.now().plusSeconds(30))) { executor.submit(task1); executor.submit(task2); } // 3 try (var executor = Executors.newVirtualThreadExecutor()) { String first = executor.invokeAny(List.of( () -> "a", () -> { throw new IOException("too lazy for work"); }, () -> "b" )); System.out.println("one result: " + first); } catch (ExecutionException e) { e.printStackTrace(); }
Collections Refueled (30:16)
JDK 9 以降の Collections Framework の改善について淡々と紹介。
簡潔なファクトリメソッド
- 不変コレクションを生成するための
of
Collections.unmodifiableList(Arrays.asList(xxx))
はList.of(xxx)
で代替できるようになったCollections.unmodifiableSet(new HashSet<>(xxx))
はSets.of(xxx)
で代替できるようになったCollections.unmodifiableMap(xxx)
にも代替案があるMap.of(k1,v1,k2,v2)
みたいな感じMap.ofEntries(Map.entry(k1, v1), Map.entry(k2, v2))
というのもある
- 冪等な複製を得るための
copyOf
- 不変コレクションは
copyOf
しても新しいオブジェクトを生成しない (知らなかった!)
- 不変コレクションは
Stream
から不変コレクションを生成するためのCollectors.toUnmodifiableXXX
イテレーション順序のランダム化
- Set および Map キーの順序の話
- HashSet と HashMap (のキー) の順序は未定義
- 新しく JDK がリリースされても順序の一貫性は保たれていた
- もし順序が変わると既存のコードが壊れる可能性がある
- 新しいファクトリメソッドが生成する不変コレクションは 順序をランダムにした
- 潜在的な順序依存性を解消するため
- 既存の HashSet や HashMap はそのまま
- 順序を保ちたければ LinkedHashSet LinkedHashMap を使うようにして欲しい
重複する要素の扱い
Set.of(a,a)
Map.of(k1,v1,k1,v2)
Map.ofEntries(...)
はIllegalArgumentException
をスローする- リテラルで記述するためのメソッドなのでコーディング誤りの可能性が高いから
空間効率について
ファクトリメソッドはサイズに応じた実装のコレクションオブジェクトを生成する(複製する?)。
要素数 | 実装 |
---|---|
0 | シングルトン |
少数(10以下?) | フィールドベースの実装 |
多数 | 配列ベースの実装 |