28
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

GraalVMでJavaをネイティブモジュールにビルドしてみる

Last updated at Posted at 2018-04-24

はじめに

ついにGraalVMの1.0 RCがリリースされました!
https://blogs.oracle.com/developers/announcing-graalvm

Java界隈の人はJava9のAOTやJava10のJITまわりの次世代基盤として、Rubyな人は爆速のRuby環境(Truffle Ruby)としてご存知なんじゃ無いでしょうか。

公式サイトには

GraalVM is a universal virtual machine for running applications written in JavaScript, Python 3, Ruby, R, JVM-based languages like Java, Scala, Kotlin, and LLVM-based languages such as C and C++.
https://www.graalvm.org/

と記載があり、あらゆる言語の統一VMを作りでバックツールやJITなどの資産活用をしようってのが目的のVM環境となります。
IBM/EclipseのORMと同じ思想を感じますね。

色々面白い事ができるのですが、その特徴の一つにJVM系言語をネイティブコンパイルできるという特徴的があります。
これにより、起動時のfootprintが悪いことで有名なJavaをかなり改善することができます。かつシングルパッケージ化もできます。
JavaをAOTコンパイルしてバイナリを作るというとGCJという懐かしのツールもありましたが、すでに最新のJavaには追従してないので、実質他には無い状態かと思います。

現在は、Community EditionとEnterprise Editionがあります。
とりあえず、インストールせずにさくりと試せるようにCE版のDocker環境を作ってみたので今回はそちらを使います。
https://hub.docker.com/r/koduki/docker-graalvm/

ネイティブモジュールにビルド

シンプルなコードをLinuxネイティブなバイナリにビルドしてみます。ビルドするコードは下記のとおり。

public class HelloWorld {
  public static void main(String args[]){
    System.out.println("Hello, World");
  }
}

下記コマンドでPullを兼ねてバージョン番号を確認。GraalVMになってる事がわかります。

$ docker run -it -v "`pwd`:/src" koduki/graalvm:1.0.0-rc1  java -version
openjdk version "1.8.0_161"
OpenJDK Runtime Environment (build 1.8.0_161-12)
GraalVM 1.0.0-rc1 (build 25.71-b01-internal-jvmci-0.42, mixed mode)

続いてふつうにJavaでコンパイルして実行。

$ docker run -it -v "`pwd`:/src" koduki/graalvm:1.0.0-rc1 javac HelloWorld.java
$ docker run -it -v "`pwd`:/src" koduki/graalvm:1.0.0-rc1 java Hello, World

当たり前ですがHello, Worldと表示されましたね。
今度はこれをLinuxバイナリにコンパイルしてみます。

$ docker run -it -v "`pwd`:/src" koduki/graalvm:1.0.0-rc1 native-image HelloWorld
Build on Server(pid: 9, port: 26681)*
   classlist:   4,335.15 ms
       (cap):   1,257.90 ms
       setup:   3,411.13 ms
  (typeflow):  12,345.25 ms
   (objects):   3,497.83 ms
  (features):      89.48 ms
    analysis:  16,130.07 ms
    universe:     541.30 ms
     (parse):   4,822.63 ms
    (inline):   2,370.80 ms
   (compile):  20,626.56 ms
     compile:  28,372.55 ms
       image:   1,507.64 ms
       write:     489.70 ms
     [total]:  54,945.94 ms
$ docker run -it -v "`pwd`:/src" koduki/graalvm:1.0.0-rc1 ./helloworld
Hello, World

helloworldというバイナリが出来ました。実行結果も同様ですね。
では、ネイティブバイナリにということで起動のフットプリントの差を見てみましょう。

Docker越しだとオーバーヘッドが大きいので、dockerに入って確認します。

$ docker run -it -v "`pwd`:/src" koduki/graalvm:1.0.0-rc1  /bin/bash
[root@d16c0ed04d03 src]# time java HelloWorld
Hello, World

real	0m0.167s
user	0m0.070s
sys	0m0.070s
[root@d16c0ed04d03 src]# time ./helloworld 
Hello, World

real	0m0.031s
user	0m0.000s
sys	0m0.000s

バイナリ版の方が速く動いてる事がわかりますね。作りが単純なのでこれは実行速度というよりはVM起動等のオーバーヘッドの差と考えて良いと思います。

まとめ

とりあえずGraalVMのnative-imageを使ってJavaをバイナリにビルドしてみました。
記事には書いてませんが、複数のクラスでもちゃんと一つのバイナリにしてくれるのでfat-jarの代用としても活用できます。

@sonodar さんが「GraalVMを試してみた」の記事で試されているように動的なモジュール読み込みを伴なうものでは動作しないようなので、SpringBootとかを使ってるWebアプリをfat-jarでは無くシングルバイナリで動かすのは厳しそうですけど。現時点では。

ただ、フットプリントが小さくなったのでScalaをはじめJVM系言語でCLIツールを作り易くなるのは個人的には結構メリットですね。
スクリプトでも良いのですが、Javaで書いた方がメンテナーが集めやすかったりする都合もあるので。いくつかのライブラリと組合わせた挙動を確認していきたいです。

あと、この記事ではCE版なのでLinuxで試していますがEE版でMacのビルドも特に問題なく出来ました。
これでWindowsまでカバー出来るようになるとまた違った事が色々出来そうですね。

それではHappy Hacking!

28
23
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?