JVM Language Summit
レポート
- GraalVM編 -
関西Javaエンジニアの会
阪田 浩一
#kanjava
About Me
• 阪田 浩一 (Koichi Sakata)
• KanJava JUG Leader/Founder
•
• Twitter: @jyukutyo
• Blog: sakatakoichi.com
• JVMになりたい人
– GCとJITコンパイラに関心
Today’s Target
GraalVMでの
ネイティブイメージ生成、
その概要と歴史を
知る
アジェンダ
• GraalVMとは
– 以前の関ジャバイベントの内容と重複します
• ネイティブイメージ生成機能の詳細
http://www.graalvm.org/
Question
GraalVMは
JVM?
GraalVMは
JVMの機能を
すべて包含します
既存のJVMにできることは
すべてできます
ベースはHotSpot VM
ただし、
JITコンパイラが
異なります
HotSpotVM
Compiler Interface
C2C1
HotSpotVM
C++
GraalVM
Compiler
Interface
GraalC1
HotSpotVM
JVMCI
Java
GraalVM ≠ Graal
Summary
• GraalVMは
–JVMにできることがすべてできる
–Java製JITコンパイラGraalを持つ
Graal JITコンパイラの
何がいいの?
Pros
• Graal上に構築した
言語実装用フレームワーク
Truffleがある
Truffle
• トラフル(トリュフ)
• 言語実装用フレームワーク
– ASTインタプリタ構築の基盤を提供する
Truffleで実装した言語を
(Graalを通し)
GraalVM上で実行できる
言語を実装して
何がうれしいの?
さまざまな言語を
実行できる環境として
高パフォーマンス
Polyglot on the JVM with Graal
さらに、その言語間で
相互に呼び出しできる
Truffleでの言語実装
HotSpot VM
JVMCI
Graal
JVM Lang Truffle
LLVMJS R Ruby
C C++
Fortran
Interpreter
GraalVMとは
高パフォーマンスな
多言語実行環境
Polyglot
=
多言語を実行できる
GraalVM
• 研究から生まれたプロダクト
– Oracle Labs
– ヨハネス・ケプラー大学
• オーストリア
• Compiler and JVM Research at JKU
– GraalやTruffleについての論文多数
• 大学内にOracle Labsのブランチがある
• オープンソース(Community Edition: 後述)
• https://github.com/oracle/graal
ついにWindowsも!
(Early Adopter Windows
Support)
Summary
• GraalVMは
–高パフォーマンスな多言語実行環境
–Polyglot VM
ネイティブイメージ化は
何なの?
Custom Part in GraalVM
• Graal
– JIT Compiler
• Truffle
– Language Implementation Framework
• Substrate VM
– Runtime Library and Tools for Java AOT Compiled
Code
AOTコンパイル
(Ahead-of-Time)
=
事前コンパイル
実行可能な
ネイティブイメージに
コンパイルする
つまり、JVM不要
クラスロードなし
起動が高速になる!
JITコンパイルしないので
ピーク時の
パフォーマンスは落ちる
OS, CPUなど
プラットフォームごとに
AOTコンパイルが必要
AOT/JITコンパイル
• AOTコンパイル(Javaでの)
– 実行前に、バイトコードから機械語に
• JITコンパイル(JVMでの)
– 実行中に、バイトコードと
プロファイルデータから機械語に
https://twitter.com/thomaswue/status/1145603781108928513
ネイティブイメージの利用想定対象
• FaaS
– AWS Lambda, Azure Functions...
– すぐに終了させる類のもの
• 多数起動するアプリケーション
– リソースの消費がコストに直結する
• とくにクラウド利用の場合
– 大規模サービスなど
– Quarkus, Micronaut, Helidonといった
対応フレームワークを利用する
もう1つ
JVM不要なため、
基本的に
ネイティブイメージは
iOS上でも動作させられる
(AppleはiOS上で
JVMを動作させることを
禁じている)
Java on iOS
• A plan to bring Java to iOS | InfoWorld
– https://www.infoworld.com/article/3407781/a-
plan-to-bring-java-to-ios.html
• Java on iOS, for real. - Gluon
– https://gluonhq.com/java-on-ios-for-real/
Summary
• Substrate VMは
–ネイティブイメージ生成時に利用
–生成したネイティブイメージを
実行する小型の仮想マシン
• GC, スレッドのスケジューリング,
コードのキャッシュなど
GraalVMは正式リリース
されているが、
ネイティブイメージは
experimentalなので注意
どんなコードでも
ネイティブイメージに
できる?
現状、
制約があります
https://github.com/oracle/graal/blob/master/substratevm/LIMITATIONS.md
そもそも、
ネイティブイメージ化は
限られたユースケースの
ためだった
初期設計時
• ユースケース
– Oracleデータベース MLEにGraalVMを組み込む
• Truffleを利用して、SQL文で多言語実行可能に
– https://www.sakatakoichi.com/entry/graalvmembeddeddb
Execute JavaScript Functions in SQL
SQL> select validator.isEmail('alice@example.com’)
from dual;
VALIDATOR.ISEMAIL('ALICE@EXAMPLE.COM’)
-------------------------------------- 1
SQL> select validator.isEmail('bob@example') from dual;
VALIDATOR.ISEMAIL('BOB@EXAMPLE’)
-------------------------------- 0
https://www.sakatakoichi.com/entry/graalvmembeddeddb
初期設計時
• Oracleデータベース向けということは…
– 同じ会社 (Oracle)内のみの利用
– サポートするOSも限定できる
– リフレクションやJNIのサポートは不要
– 初期化の速さと省メモリが必須
初期設計時
制約は多いが、
うまく機能した
ネイティブイメージは
いわばオマケだった
(個人的所感)
それが
GraalVMの1機能となり、
Oracleデータベース向け
という前提は
なくなった
改善を進めており、
制約のいくつかは
解消している
リフレクションとJNI
設定ファイル (JSON)を
用意すれば
利用可能
リフレクションサンプル
[
{
"name" : "java.lang.String",
"fields" : [
{ "name" : "value", "allowWrite" : true }
],
"methods" : [
{ "name" : "format", "parameterTypes" : ["java.lang.String",
"java.lang.Object[]"] }
]
}
]
事前に
使用箇所を
全部調べるの!?
Tracing Agent
リフレクションやJNIの
使用をトレースし、
設定ファイルを出力する
エージェント
Tracing Agent
• JVMTIエージェントが付属している
$ java -agentlib:native-image-agent...
アプリケーションのコードを
網羅するテストコードを実行し、
設定ファイルを出力させる
現実的には、
手作業での反映も
必要となる
クラス初期化での
課題
ネイティブイメージ生成プロセス
• インプット
– Javaクラスすべて
– ライブラリすべて
– VM (SubstrateVM)
ネイティブイメージ生成プロセス
アプリケーション
ライブラリ
JDK
SubstrateVM
下記の繰り返し:
解析ポイント
↓
初期化処理実行
↓
ヒープのスナップショット生成
ELFファイル
コード
(textセクション)
イメージヒープ
(dataセクション)
そもそもは、
イメージ生成時に
全クラスを
初期化していた
初期化の課題
import java.util.Date;
class Startup {
static final Date TIME = new Date();
}
class HelloStartupTime {
public static void main(String[] args) {
System.out.println("Startup: " + Startup.TIME);
System.out.println("Now: " + new Date());
}
}
実行結果
$ ./hellostartuptime
Startup: Fri Aug 16 20:31:06 JST 2019
Now: Fri Aug 16 20:31:32 JST 2019
現在は指定できる
• --initialize-at-build-time=[クラス名]
• --initialize-at-run-time=[クラス名]
$ ./native-image --initialize-at-build-time=Startup HelloStartupTime
$ ./hellostartuptime
Startup: Fri Aug 16 20:31:06 JST 2019
Now: Fri Aug 16 20:31:32 JST 2019
$ ./native-image --initialize-at-run-time=Startup HelloStartupTime
$ ./hellostartuptime
Startup: Fri Aug 16 20:38:24 JST 2019
Now: Fri Aug 16 20:38:24 JST 2019
ただし、実行時の
初期化は
パフォーマンスに
影響する
クラスの初期化は
トリッキーであり、
思ったように
動作しない場合も
まだある
ネイティブイメージ化のサポート
• Linux, macOSのみ
– Windows対応は課題だが、多くの作業が必要
• Java 8のみ
– Java 8, 11, 13で異なる部分がある
– GraalVM自体がJava 8バージョンのみ
– GraalVM自体のJava 11対応は作業中
ネイティブイメージ化のサポート
• 現状 x64のみ
– GraalVM自体は x64, AArch64, Sparcをサポート
• LLVMの利用も検討中だが…
– 代償を伴うとのこと
ライブラリのネイティブイメージ対応
• ライブラリのMETA-INF/native-image
– 設定ファイルを配置する
– Nettyなど対応済みのものも
Wrap Up
GraalVM is AWESOME!
Fin.

Introduction to GraalVM and Native Image