Slide 1

Slide 1 text

Java 16新機能 言語とAPIを中心に あとAlpine Linux JJUG Night Seminar 2021/3/16 LINE Fukuoka きしだ なおき

Slide 2

Slide 2 text

Java 16 • 2021/3/16リリース • non-LTS • 次は17(Sept.2021) • 17個のJEP http://openjdk.java.net/projects/jdk/16/

Slide 3

Slide 3 text

Java 16 • 2021/3/16リリース • non-LTS • 次は17(Sept.2021) • 17個のJEP http://openjdk.java.net/projects/jdk/16/ LTS(Long Term Support) 長期サポート 6バージョンごとにLTSが設定されて長期間の サポートが行われる。 現在のLTSは11で、次回は17。 15はLTSではないので16が出ればバグ修正など は行われなくなる。

Slide 4

Slide 4 text

Java 16 • 2021/3/16リリース • non-LTS • 次は17(Sept.2021) • 17個のJEP http://openjdk.java.net/projects/jdk/16/

Slide 5

Slide 5 text

Java 16 • 2021/3/16リリース • non-LTS • 次は17(Sept.2021) • 17個のJEP http://openjdk.java.net/projects/jdk/16/ JEP(JDK Enhancement Proposal) 機能改善のまとめ 主な仕様変更はJEPとしてまとめられている

Slide 6

Slide 6 text

Java 16 • 2021/3/16リリース • non-LTS • 次は17(Sept.2021) • 17個のJEP • 更新4個 • うち3個が正式化 http://openjdk.java.net/projects/jdk/16/ 正式化 正式化 更新 更新 正式化

Slide 7

Slide 7 text

Java 16 • 2021/3/16リリース • non-LTS • 次は17(Sept.2021) • 17個のJEP • 更新4個 • うち3個が正式化 http://openjdk.java.net/projects/jdk/16/ 正式化 正式化 更新 更新 正式化 Javaの試用機能 大きな新機能について試用版として導入することで フィードバックを得やすくしてよりよい機能を提供 できるようにする • 言語機能:Preview • API:Incubator • JVM機能:Experimental 17LTSにはPreviewは残さない意向に見える

Slide 8

Slide 8 text

JEP • 言語仕様 • Pattern Matching for instanceof • Records • Sealed Classes(Second Preview) • Warnings for Value-Based Classes • API • Foreign Memory Access API (Third Incubator) • Vector API(Incubator) • Foreign Linker API(Incubator) • Unix-Domain Socket Channels • Tool • Packaging Tool • JVM • ZGC: Concurrent Thread-Stack Processing • Elastic Metaspace • Strongly Encapsulate JDK Internals by Default • OpenJDK • Migrate from Mercurial to Git • Migrate to GitHub • Enable C++14 Language Features • Alpine Linux Port • Windows/AArch64 Port

Slide 9

Slide 9 text

JEP • 言語仕様 • Pattern Matching for instanceof • Records • Sealed Classes(Second Preview) • Warnings for Value-Based Classes • API • Foreign Memory Access API (Third Incubator) • Vector API(Incubator) • Foreign Linker API(Incubator) • Unix-Domain Socket Channels • Tool • Packaging Tool • JVM • ZGC: Concurrent Thread-Stack Processing • Elastic Metaspace • Strongly Encapsulate JDK Internals by Default • OpenJDK • Migrate from Mercurial to Git • Migrate to GitHub • Enable C++14 Language Features • Alpine Linux Port • Windows/AArch64 Port

Slide 10

Slide 10 text

ダウンロードサイト • Oracle OpenJDK • http://jdk.java.net/16/ • AdoptOpenJDK • https://adoptopenjdk.net/?variant=openjdk16&jvmVariant=hotspot • Amazon Corretto • https://github.com/corretto/corretto-jdk/releases/tag/16.0.0.36.1 • Azul Zulu Community • https://jp.azul.com/downloads/zulu-community/?version=java-16- ea&architecture=x86-64-bit&package=jdk • Liberica JDK • https://bell-sw.com/pages/java-16/ • Oracle JDK • https://www.oracle.com/java/technologies/javase-jdk16-downloads.html

Slide 11

Slide 11 text

言語仕様 • Pattern Matching for instanceof(Standard) • Records(Standard) • Sealed Classes(Second Preview) • Warnings for Value-Based Classes

Slide 12

Slide 12 text

Pattern Matching for instanceof(Standard) • Kotlinのスマートキャストのような機能 Object o = "test"; if (o instanceof String s) { System.out.println(s.length()); } Object o = "test"; if (o instanceof String) { String s = (String) o; System.out.println(s.length()); }

Slide 13

Slide 13 text

Records(Standard) • データをやりとりするための型 • イミュータブル(値が変更できない) • 名前付きタプル • Case class(Scala) やData class(Kotlin), @Value(Lombok)

Slide 14

Slide 14 text

Recordの定義 public record Rec(String name, int count) {} public final class Rec extends Record { private final String name; private final int count; Rec(String name, int count) { this.name = name; this.count = count; } String name() { return name; } String count() { return count; } // toString, equals, hashCode } recordで宣言

Slide 15

Slide 15 text

Recordの定義 public record Rec(String name, int count) {} public final class Rec extends Record { private final String name; private final int count; Rec(String name, int count) { this.name = name; this.count = count; } String name() { return name; } String count() { return count; } // toString, equals, hashCode } 要素(コンポーネント)を定義

Slide 16

Slide 16 text

Recordの定義 public record Rec(String name, int count) {} public final class Rec extends Record { private final String name; private final int count; Rec(String name, int count) { this.name = name; this.count = count; } String name() { return name; } String count() { return count; } // toString, equals, hashCode } 中かっこが必要 追加のメソッドなどの定義も可

Slide 17

Slide 17 text

Recordの定義 public record Rec(String name, int count) {} public final class Rec extends Record { private final String name; private final int count; Rec(String name, int count) { this.name = name; this.count = count; } String name() { return name; } String count() { return count; } // toString, equals, hashCode } 暗黙にfinal

Slide 18

Slide 18 text

Recordの定義 public record Rec(String name, int count) {} public final class Rec extends Record { private final String name; private final int count; Rec(String name, int count) { this.name = name; this.count = count; } String name() { return name; } String count() { return count; } // toString, equals, hashCode } java.lang.Recordを継承

Slide 19

Slide 19 text

Recordの定義 public record Rec(String name, int count) {} public final class Rec extends Record { private final String name; private final int count; Rec(String name, int count) { this.name = name; this.count = count; } String name() { return name; } String count() { return count; } // toString, equals, hashCode } コンポーネントに 対応するフィールド private final

Slide 20

Slide 20 text

Recordの定義 public record Rec(String name, int count) {} public final class Rec extends Record { private final String name; private final int count; Rec(String name, int count) { this.name = name; this.count = count; } String name() { return name; } String count() { return count; } // toString, equals, hashCode } コンストラクタが定義される

Slide 21

Slide 21 text

Recordの定義 public record Rec(String name, int count) {} public final class Rec extends Record { private final String name; private final int count; Rec(String name, int count) { this.name = name; this.count = count; } String name() { return name; } String count() { return count; } // toString, equals, hashCode } コンポーネントと同名の アクセスメソッド getterではない

Slide 22

Slide 22 text

Recordの定義 public record Rec(String name, int count) {} public final class Rec extends Record { private final String name; private final int count; Rec(String name, int count) { this.name = name; this.count = count; } String name() { return name; } String count() { return count; } // toString, equals, hashCode } オブジェクトの基本メソッドも 実装される

Slide 23

Slide 23 text

Recordの利用 • 利用時は普通のクラスと同様 Rec r = new Rec("Java", 15);

Slide 24

Slide 24 text

カノニカルコンストラクタ • コンストラクタの定義では、引数にコンポーネントをその型で その順番で、そしてそれだけを書く必要がある • コンポーネントに対応する内部フィールドを必ず初期化しない といけない • カノニカル(正規)コンストラクタ

Slide 25

Slide 25 text

カノニカル(正規)コンストラクタ • コンポーネントと同じパラメータとフィールド初期化が必要 record Rec(String name, int count) { Rec(String name, int count) { this.name = name; this.count = Math.max(count, 0); } } コンポーネントと同じ パラメータが必要

Slide 26

Slide 26 text

カノニカル(正規)コンストラクタ • コンポーネントと同じパラメータとフィールド初期化が必要 record Rec(String name, int count) { Rec(String name, int count) { this.name = name; this.count = Math.max(count, 0); } } フィールド初期化が必須

Slide 27

Slide 27 text

コンパクトコンストラクタ • 必ず書かないといけないものは省略していいのでは? record Rec(String name, int count) { Rec { count = Math.max(count, 0); } } パラメータを省略

Slide 28

Slide 28 text

コンパクトコンストラクタ • 必ず書かないといけないものは省略していいのでは? record Rec(String name, int count) { Rec { count = Math.max(count, 0); } } フィールドを初期化してはいけない

Slide 29

Slide 29 text

Sealed Classes(2nd Preview) • 継承できるクラスを限定する • shield(盾) classではなくてsealed(密閉された) class public abstract sealed class Shape permits Circle, Rectangle, Square {...}

Slide 30

Slide 30 text

Preview機能 • 言語機能の試用版 • 基本的にpreview, second previewの2回のpreviewを経て正式 化する • 正式化までに3バージョン必要 • 明確な決まりがあるわけではない • javacやjavaコマンドなどで`--enable-preview`が必要 • `-source`でのバージョン指定も必要 jshell> sealed class Hoge{} | エラー: | シール・クラスはプレビュー機能であり、デフォルトで無効になっています。 | (シール・クラスを有効にするには--enable-previewを使用します) | sealed class Hoge{} | ^

Slide 31

Slide 31 text

( ´∀`)<シールドクラス • 公式にはシール・クラス? jshell> sealed class Hoge{} | エラー: | シール・クラスはプレビュー機能であり、デフォルトで無効になっています。 | (シール・クラスを有効にするには--enable-previewを使用します) | sealed class Hoge{} | ^

Slide 32

Slide 32 text

現状では使い道なし • 本当は次のように書けるといい • Pattern matching for switchなどが来れば便利に(Java 18かな) String getName(Shape s) { if (s instanceof Circle) { return "円"; } else if (s instanceof Rectangle) { return "四角"; } else if (s instanceof Square) { return "正方形"; } }

Slide 33

Slide 33 text

Sealed Classesの階層 • Sealed Classを継承する場合、sealed・final・non-sealedの いずれかが必要 • recordは暗黙的にfinal Hoge Foo Bar Baz sealed 要 sealed 要 final or non-sealed 要 final or non-sealed MyBaz Bazがnon-sealedであれば 継承できる。sealされない sealed class Hoge permits Foo, Bar {} final class Foo extends Hoge {} sealed class Bar extends Hoge permits Baz {} non-sealed class Baz extends Bar {} class MyBaz extends Baz {}

Slide 34

Slide 34 text

non-sealed • ハイフン入りキーワード! • 実際はキーワードではない • switch式のときにbreak-withが検討されていた • package-privateなども可能

Slide 35

Slide 35 text

API • Vector API(Incubator) • Foreign Memory Access API(3rd Incubator) • Foreign Linker API(Incubator) • Unix-Domain Socket Channels

Slide 36

Slide 36 text

Vector API(Incubator) • AVX命令のような、複数のデータに対する計算を同時に行う 命令(SIMD - Single Instruction Multiple Data)をJavaから利用 import jdk.incubator.vector.*; static final VectorSpecies SPECIES = FloatVector.SPECIES_256; void vectorComputation(float[] a, float[] b, float[] c) { // SPECIES.length() = 256bit / 32bit -> 8 for (int i = 0; i < a.length; i += SPECIES.length()) { // 端数がマスクされる // a.lengthが11でiが8のとき最初の3つしか要素がないので [TTT.....] VectorMask m = SPECIES.indexInRange(i, a.length); FloatVector va = FloatVector.fromArray(SPECIES, a, i, m); FloatVector vb = FloatVector.fromArray(SPECIES, b, i, m); FloatVector vc = va.mul(va). add(vb.mul(vb)). neg(); vc.intoArray(c, i, m); } }

Slide 37

Slide 37 text

どんなハードウェアで使える? • IntelハイエンドだとAVX512に対応 • double(64bit) x 8 • なんだけど、i7 7820Xでdouble x 4までしか使えず • ほかのi7やi5などは256bit • M1は128bit • double x 2 • float x 4

Slide 38

Slide 38 text

• SmallPT レイトレやってみる https://github.com/kishida/smallpt4j/blob/vector/src/main/java/naoki/smallpt/SmallPT.java public class SmallPT { private static final int SAMPLES_DEFAULT = 40; private static final VectorSpecies SPECIES = DoubleVector.SPECIES_256; static DoubleVector fromValues(double x, double y, double z) { return DoubleVector.fromArray(SPECIES, new double[]{x, y, z, 0}, 0); } static DoubleVector normalize(DoubleVector v) { double dist = sqrt(v.mul(v).reduceLanes(VectorOperators.ADD)); return v.div(dist); } static double dot(DoubleVector v, DoubleVector b) { return v.mul(b).reduceLanes(VectorOperators.ADD); } // cross: static VectorShuffle yzx = VectorShuffle.fromValues(SPECIES, 1, 2, 0, 3); static DoubleVector mod(DoubleVector v, DoubleVector b) { // return v.rearrange(yzx).mul(b.rearrange(zxy)).sub(v.rearrange(zxy).mul(b.rearrange(yzx))); return v.mul(b.rearrange(yzx)).sub(v.rearrange(yzx).mul(b)).rearrange(yzx); }

Slide 39

Slide 39 text

結果 • Vector版 9.7秒 • 通常版 6.3秒 • おそい・・・ • JITがきいてない • 複雑な処理ではまだパフォーマンスが出なさそう

Slide 40

Slide 40 text

Foreign memory Access API(3rd incubator) • 大量データを処理するために、GCで管理されないメモリを 確保する • 標準ではないUnsafeを使っていたものを標準APIで実現する • --add-modules jdk.incubator.foreign が必要 import jdk.incubator.foreign.*; try (MemorySegment segment = MemorySegment.allo cateNative(100)) { for (int i = 0 ; i < 25 ; i++) { MemoryAccess.setIntAtOffset(i * 4, i); } }

Slide 41

Slide 41 text

One more thing!

Slide 42

Slide 42 text

Stream.toList()

Slide 43

Slide 43 text

Stream.toList() • collector(Collectors.toUnmodifiableList())と書く必要 がなくなった! • 変更不可のリストなのでCollectors.toList()を置き換える ときは注意 C:¥Users¥naoki>java¥jdk¥jdk-16¥bin¥jshell | JShellへようこそ -- バージョン16 | 概要については、次を入力してください: /help intro jshell> Stream.of("a","b","c").toList() $1 ==> [a, b, c] jshell> /var $1 | List $1 = [a, b, c] jshell> $1.getClass() $2 ==> class java.util.ImmutableCollections$ListN

Slide 44

Slide 44 text

OpenJDK • Windows/AArch64 Port • Alpine Linux Port

Slide 45

Slide 45 text

ARM Mac対応は17っぽい • まだ一覧には のってない

Slide 46

Slide 46 text

Alpine Linuxで最小Docker Imageを作る

Slide 47

Slide 47 text

Alpine Linux • musl • c標準ライブラリ • glibc互換 • コンパクトに整理されている • ヘッダが人間にも読める • glibcは#ifdefたくさんで読みにくい • busybox • すべてのコマンドがbusyboxにsymbolic link • apk • パッケージ管理

Slide 48

Slide 48 text

16にはまだAlpineバイナリがない・・・ • JDK 16 RC http://jdk.java.net/16/

Slide 49

Slide 49 text

では自分でビルドだ • bash configure make • ソースはGitHub https://github.com/openjdk/jdk/tree/jdk-16+36

Slide 50

Slide 50 text

ビルドエラー (T^T) • allocaの戻り値を使っていないという警告が

Slide 51

Slide 51 text

パッチ • ダミー変数に割り当てる 672c672 < alloca(((pid ^ counter++) & 7) * 128); --- > int* dummy = (int*)alloca(((pid ^ counter++) & 7) * 128);

Slide 52

Slide 52 text

結構大きい • Spring Boot+Spring MVCのHello Worldを動かす • 961MB

Slide 53

Slide 53 text

jlinkで実行環境を最適化 • 必要なモジュールだけを持つJava実行環境をつくる • jdepsで必要なモジュールを確認する • Springのようなfat-jarでは一度展開してライブラリjarを取り出して おく必要がある > jlink --compress 2 --strip-debug --no-header-files --no-man-pages --output /src/jre --add-modules java.base,java.desktop,java.instrument,java.management.rmi,java.naming,java.pref s,java.scripting,java.security.jgss,java.sql,jdk.httpserver,jdk.jfr,jdk.unsuppor ted

Slide 54

Slide 54 text

77MB • 77MBのイメージができた

Slide 55

Slide 55 text

参考 • UbuntuやJibを使ってみる

Slide 56

Slide 56 text

Shenandoahとかいらなくない? • 使わない機能がたくさんある • Javaには6つのGCがある • 1つしか使わない • 削ってみる

Slide 57

Slide 57 text

--disable-jvm-feature • 使わないものを無効にしてみる bash configure --disable-jvm-feature-aot --disable-jvm-feature-graal --disable- jvm-feature-parallelgc --disable-jvm-feature-shenandoahgc --disable-jvm-feature- zgc --disable-jvm-feature-epsilongc --disable-jvm-feature-jvmci --disable-jvm- feature-jni-check --disable-jvm-feature-dtrace

Slide 58

Slide 58 text

結果:そんな小さくない • 74MB

Slide 59

Slide 59 text

もっと削ってみる • JITいらんくない? • Serial GCでよくない? • 管理しねーし bash configure --disable-jvm-feature-aot --disable-jvm-feature-graal -- disable-jvm-feature-parallelgc --disable-jvm-feature-shenandoahgc -- disable-jvm-feature-zgc --disable-jvm-feature-epsilongc --disable-jvm- feature-jvmci --disable-jvm-feature-jni-check --disable-jvm-feature-dtrace --disable-jvm-feature-cds --disable-jvm-feature-compiler1 --disable-jvm- feature-compiler2 --disable-jvm-feature-jvmti --disable-jvm-feature-jfr -- disable-jvm-feature-management --disable-jvm-feature-g1gc --disable-jvm- feature-services --disable-jvm-feature-nmt --disable-jvm-feature-vm-structs --disable-jvm-feature-link-time-opt

Slide 60

Slide 60 text

60MB! • だいぶ小さくなった

Slide 61

Slide 61 text

結果 • すごく小さいです! 0 50 100 150 200 250 Alpine最小 Alpineほどほど Alpine Ubuntu Jib

Slide 62

Slide 62 text

うごいた! • 動きます • でも遅い • 2秒→9秒

Slide 63

Slide 63 text

まとめ • recordとtoList便利そう