2019年9月16~19日にかけての4日間、米サンフランシスコのMoscone CenterにおいてOracle主催の技術カンファレンス「Oracle Code One 2019」が開催されました。Oracle Code Oneは2年前までは「JavaOne」の名称で開催されていたもので、Javaを中心とした開発者向けのセッションやブース展示、交流会などが行われる年次イベントです。
今年のCode Oneで話題の中心となっていたのは、2018年にOracleがリリースした「GraalVM」です。GraalVMは、Java仮想マシン(以下、JVM)およびJIT(Just-in-Time)/AOT(Ahead-of-Time)コンパイラの技術を利用して作成された多言語対応の汎用仮想マシンです。昨年のCode Oneレポートでも『【Oracle Code Oneレポート】Oracleが開発中の仮想マシン「GraalVM」で何ができるか』としてその活用方法や具体的な事例などを紹介しましたが、それから1年経ち、いまやJavaの未来を左右すると言えるほどまでにその存在感を増してきています。
Community EditionとEnterprise Edition
GraalVMはOracleのプロダクトであり、Community Edition(CE)とEnterprise Edition(EE)の2種類が用意されています。CEの方はGitHubにソースコードが公開されており、無償で利用することができます。EEの方は有償ですが、CEに比べて高性能でメモリフットプリントが小さいなどといった強みがあるほか、GraalVMチームによる直接のサポートも提供されます。
なお、Oracle Cloud Infrastructure(OCI)のユーザはGraalVM EEを追加料金無しで利用できます。これには、先日スタートしたOCIの一部機能を無償で利用できる「Oracle Cloud Free Tier」のユーザも含まれるとのことです。
GraalVMに期待されているおもな役割
GraalVMが何をするためのツールなのかを一言で説明するのは少し大変です。昨年のレポートでも説明しているように、GraalVM自身は複数の技術要素を組み合わせて構成されており、実にさまざまな活用方法が考えられるからです。GraalVMのプロジェクトリードを務めるOracleのThomas Wuerthinger氏は、プロジェクトのゴールとして次の4つの要素を挙げています。
- あらゆる言語のための高性能な抽象化層を提供する
- JVMベース言語用の低フットプリントなAhead-of-Timeモードを実現する
- 言語の相互運用性を高める多言語ツールを提供する
- プログラムをネイティブ環境にシンプルに組み込めるようにする
もう少し噛み砕いて説明すると、現在GraalVMに期待されているおもな役割は、大きく3つに分けることができます。
1つは高性能なJITコンパイラを持つ多言語対応の実行環境です。GraalVMには「Truffle」と呼ばれる任意のプログラミング言語のインタプリタを実装するためのフレームワークが含まれており、これによって、JavaやJVM言語(ScalaやKotlinのようなもともとJVMで動作するように作られた言語)以外の言語も、JVM上で動作するように実装できます。現在、Truffleを利用してJavaScriptやRubyといった主要な言語のインタプリタの実装が進められているところです。
JITコンパイラは、JVM標準のHotSpotに代わって、「Graal」と呼ばれる独自のJITコンパイラが搭載されています。GraalはTruffleの生成するASTを高いパフォーマンスで実行できるように設計されているため、この2つを組み合わせることで、理想的にはあらゆる言語を高性能なJIT環境上で動かすことができるというわけです。
GraalVMに求められる2つ目の大きな役割が、複数のプログラミング言語を容易に相互運用できるようにすることです。GraalVMでは、Javaプログラム内で他の言語のコードを実行したり、逆に他の言語からJavaのオブジェクトを呼び出したりすることができるライブラリが提供されます。これによって、さまざまな言語の良い部分を組み合わせた実装を考えることができます。
3つ目に求められているのが、Javaプログラムのネイティブ実行ファイルの作成ツールとしての役割です。GraalVMには、Javaのプログラムを事前に特定の環境用のネイティブバイナリにコンパイルしておく、ネイティブイメージ作成ツールが用意されています。通常のJavaプログラムは、ソースコードからコンパイルして生成されたJavaバイトコードを実行時にJVMが読み込んで処理します。
これに対してネイティブイメージは、Javaバイトコードではなく実行可能なバイナリにコンパイルされたファイルになります。GraalVMのネイティブイメージはJVMがなくても実行でき、Javaクラスをロードして初期化する必要もないため、極めて高速に起動することができます。ネイティブイメージは、特にスタンドアロン型のアプリケーションを提供する場合や、マイクロサービスのようにインスタンスの起動と停止を頻繁に繰り返すような用途での活用が期待されています。
ネイティブイメージ化はAOTによる高速化が大きな課題
前述の3つの役割の中でも、ネイティブイメージの作成は特にいまホットな話題と言えます。従来のJVMの仕組みは汎用性が高い一方で、起動時間が遅いという構造上の課題を抱えていました。ネイティブイメージはその課題を解消するための極めて強力な武器になります。
GraalVMのネイティブイメージはJVM無しで実行できる点が特徴ですが、これはJVMと同様の役割を持った「SubstrateVM」と呼ばれる小型仮想マシンを使うことで実現されています。アプリケーションのクラスはネイティブイメージ作成時に実行可能なバイナリにコンパイルされ、SubstrateVMと一緒にパッケージされて提供されます。
ネイティブイメージの作成する場合、事前にアプリケーションの初期化を行うため、起動時間やメモリフットプリントという点では極めて有利ですが、その一方でJITによる実行時最適化ができないというデメリットもあります。その代わりに、AOTコンパイル技術を駆使して事前コンパイル時にコードを分析して最適化を行います。
ただし、現状ではAOTによる最適化はピーク時のスループットや最大レイテンシの削減という点で、JITに対して大きく溝を空けられています。ネイティブイメージをより強力なものにするためにはAOTの性能向上が必要であり、GraalVMプロジェクトでも重要な課題としてさまざまな取り組みが行われているとのことです。
将来的な目標としてはAOTでもJITと同等のスループット/レイテンシ削減を実現したいと、Thomas Wuerthinger氏は語っています。
そのための取り組みの1つに、「Profile-Guided Optimizations(PGO)」があります。これは、事前に実際にアプリケーションを実行してワークロード情報を取得しておき、それをネイティブイメージ作成時に最適化に活用するというものです。PGOはとしてEnterprise Editionのバージョン19.2より実際に導入されました。
今後のリリース予定
GraalVMは、現在3ヵ月ごとのメジャーリリースというサイクルで開発が進められています。その年の最後にリリースされたバージョンは、LTSとして翌年1年間はサポートが提供されることになります。
直近では、2019年10月15日にバージョン19.2.1が、11月19日にバージョン19.3がリリースされます。現行バージョンはJava 8のみにしか対応していませんが、バージョン19.3ではJava 11がサポートされる予定です。