LoginSignup
55
26

More than 5 years have passed since last update.

GraalVMを試してみた

Last updated at Posted at 2018-04-20

Oracleが発表した複数言語の共通VM GraalVM を試してみた。

GraalVMをインストール

Community EditionだとLinuxのみサポートのためVirtual BoxでサクっとCentOS7のVMを作成した。
作成したVMにSSHログインしてGraalVMをインストールする。

curl -sSL https://github.com/oracle/graal/releases/download/vm-1.0.0-rc1/graalvm-ce-1.0.0-rc1-linux-amd64.tar.gz > graalvm-ce-1.0.0-rc1-linux-amd64.tar.gz

tar zxf graalvm-ce-1.0.0-rc1-linux-amd64.tar.gz
mv graalvm-1.0.0-rc1 /var/lib/

cat <<-'__EOT__' > /etc/profile.d/graalvm.sh
#!/bin/sh
export GRAALVM_HOME=/var/lib/graalvm-1.0.0-rc1
export JAVA_HOME=$GRAALVM_HOME
export PATH=$GRAALVM_HOME/bin:$PATH
__EOT__

. /etc/profile
[root@centos-local demo]# 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)
[root@centos-local demo]#

インストール完了。簡単。

Spring Bootを試してみる

Spring Initializrwebだけ含めたGradleのパッケージをダウンロードして以下のソースを作成。
グループIDとアーティファクトIDはデフォルトのcom.example:demoのまま。

ダウンロードしたdemo.zipをVM上にscpして解凍。
コントローラクラスを実装する。

unzip -q demo.zip
cd demo
vi src/main/java/com/example/demo/DemoController.java
src/main/java/com/example/demo/DemoController.java
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
    @GetMapping("/")
    public String demo() {
        return "demo";
    }
}

bootRunしてみる。

[root@centos-local demo]# ./gradlew bootRun
...
2018-04-20 11:34:05.673  INFO 2814 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-04-20 11:34:05.775  INFO 2814 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-04-20 11:34:05.780  INFO 2814 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 13.727 seconds (JVM running for 15.251)

起動したらブラウザから http://VMのIPアドレス:8080 にアクセスして確認。
成功。

native-imageによるコンパイルを試す

まずは実行可能なjarをビルドする。


[root@centos-local demo]# ./gradlew  assemble
Starting a Gradle Daemon, 1 busy Daemon could not be reused, use --status for details

BUILD SUCCESSFUL in 26s
3 actionable tasks: 2 executed, 1 up-to-date

native-imageコマンドを実行。

[root@centos-local demo]# native-image -jar build/libs/demo-0.0.1-SNAPSHOT.jar
Build on Server(pid: 2664, port: 26681)*
   classlist:   3,887.24 ms
       (cap):     739.46 ms
       setup:   1,694.07 ms
fatal error: com.oracle.svm.core.util.VMError$HostedError: java.io.IOException: Cannot run program "gcc" (in directory "/tmp/SVM-5836691607051554173"): error=2, そのようなファイルやディレクトリはありません
    at com.oracle.svm.core.util.VMError.shouldNotReachHere(VMError.java:68)
    at com.oracle.svm.hosted.c.codegen.CCompilerInvoker.compileAndParseError(CCompilerInvoker.java:83)
    at com.oracle.svm.hosted.c.CAnnotationProcessor.compileQueryCode(CAnnotationProcessor.java:124)
    at com.oracle.svm.hosted.c.CAnnotationProcessor.process(CAnnotationProcessor.java:80)
    at com.oracle.svm.hosted.c.NativeLibraries.finish(NativeLibraries.java:340)
    at com.oracle.svm.hosted.NativeImageGenerator.processNativeLibraryImports(NativeImageGenerator.java:1294)
    at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:518)
    at com.oracle.svm.hosted.NativeImageGenerator.lambda$run$0(NativeImageGenerator.java:381)
    at java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1386)
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
    at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
    at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: java.io.IOException: Cannot run program "gcc" (in directory "/tmp/SVM-5836691607051554173"): error=2, そのようなファイルやディレクトリはありません
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
    at com.oracle.svm.hosted.c.codegen.CCompilerInvoker.startCommand(CCompilerInvoker.java:114)
    at com.oracle.svm.hosted.c.codegen.CCompilerInvoker.startCompiler(CCompilerInvoker.java:96)
    at com.oracle.svm.hosted.c.codegen.CCompilerInvoker.compileAndParseError(CCompilerInvoker.java:61)
    ... 11 more
Caused by: java.io.IOException: error=2, そのようなファイルやディレクトリはありません
    at java.lang.UNIXProcess.forkAndExec(Native Method)
    at java.lang.UNIXProcess.<init>(UNIXProcess.java:247)
    at java.lang.ProcessImpl.start(ProcessImpl.java:134)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
    ... 14 more
Error: Processing image build request failed

gccがないと怒られたので入れる。

yum install -y gcc

再チャレンジ。

[root@centos-local demo]# native-image -jar build/libs/demo-0.0.1-SNAPSHOT.jar
Build on Server(pid: 2664, port: 26681)
   classlist:     819.55 ms
       (cap):     610.39 ms
       setup:     930.25 ms
error: Error compiling query code (in /tmp/SVM-1219850078254730049/PosixDirectives.c). Compiler command  gcc /tmp/SVM-1219850078254730049/PosixDirectives.c -o /tmp/SVM-1219850078254730049/PosixDirectives output included error: [/tmp/SVM-1219850078254730049/PosixDirectives.c:60:18: 致命的エラー: zlib.h: そのようなファイルやディレクトリはありません,  #include <zlib.h>,                   ^, コンパイルを停止しました。]
    C file contents around line 60:
    /tmp/SVM-1219850078254730049/PosixDirectives.c:59: #include <unistd.h>
    /tmp/SVM-1219850078254730049/PosixDirectives.c:60: #include <zlib.h>
    /tmp/SVM-1219850078254730049/PosixDirectives.c:61: #include <arpa/inet.h>
Error: Processing image build request failed

zlibがないと怒られたので入れる。

yum install -y zlib-devel

再々チャレンジ。

[root@centos-local demo]# native-image -jar build/libs/demo-0.0.1-SNAPSHOT.jar
Build on Server(pid: 2664, port: 26681)
   classlist:     590.30 ms
       (cap):   1,855.36 ms
       setup:   3,616.40 ms
    analysis:  20,212.31 ms
error: unsupported features in 3 methods
Detailed message:
Error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Unsupported constructor java.lang.ClassLoader.<init>(ClassLoader) is reachable: The declaring class of this element has been substituted, but this element is not present in the substitution class
To diagnose the issue, you can add the option -H:+ReportUnsupportedElementsAtRuntime. The unsupported element is then reported at run time when it is accessed the first time.
Trace:
    at parsing java.security.SecureClassLoader.<init>(SecureClassLoader.java:76)
Call path from entry point to java.security.SecureClassLoader.<init>(ClassLoader):
    at java.security.SecureClassLoader.<init>(SecureClassLoader.java:76)
    at java.net.URLClassLoader.<init>(URLClassLoader.java:100)
    at org.springframework.boot.loader.LaunchedURLClassLoader.<init>(LaunchedURLClassLoader.java:50)
    at org.springframework.boot.loader.Launcher.createClassLoader(Launcher.java:74)
    at org.springframework.boot.loader.Launcher.createClassLoader(Launcher.java:64)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:49)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
    at com.oracle.svm.reflect.proxies.Proxy_1_JarLauncher_main.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.oracle.svm.core.JavaMainWrapper.run(JavaMainWrapper.java:199)
    at Lcom/oracle/svm/core/code/CEntryPointCallStubs;.com_002eoracle_002esvm_002ecore_002eJavaMainWrapper_002erun_0028int_002corg_002egraalvm_002enativeimage_002ec_002etype_002eCCharPointerPointer_0029(generated:0)
Error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Unsupported field java.net.URL.handlers is reachable
To diagnose the issue, you can add the option -H:+ReportUnsupportedElementsAtRuntime. The unsupported element is then reported at run time when it is accessed the first time.
Trace:
    at parsing java.net.URL.setURLStreamHandlerFactory(URL.java:1118)
Call path from entry point to java.net.URL.setURLStreamHandlerFactory(URLStreamHandlerFactory):
    at java.net.URL.setURLStreamHandlerFactory(URL.java:1110)
    at org.springframework.boot.loader.jar.JarFile.resetCachedUrlHandlers(JarFile.java:392)
    at org.springframework.boot.loader.jar.JarFile.registerUrlProtocolHandler(JarFile.java:382)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:48)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
    at com.oracle.svm.reflect.proxies.Proxy_1_JarLauncher_main.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.oracle.svm.core.JavaMainWrapper.run(JavaMainWrapper.java:199)
    at Lcom/oracle/svm/core/code/CEntryPointCallStubs;.com_002eoracle_002esvm_002ecore_002eJavaMainWrapper_002erun_0028int_002corg_002egraalvm_002enativeimage_002ec_002etype_002eCCharPointerPointer_0029(generated:0)
Error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Unsupported method java.security.ProtectionDomain.getCodeSource() is reachable: The declaring class of this element has been substituted, but this element is not present in the substitution class
To diagnose the issue, you can add the option -H:+ReportUnsupportedElementsAtRuntime. The unsupported element is then reported at run time when it is accessed the first time.
Trace:
    at parsing org.springframework.boot.loader.Launcher.createArchive(Launcher.java:118)
Call path from entry point to org.springframework.boot.loader.Launcher.createArchive():
    at org.springframework.boot.loader.Launcher.createArchive(Launcher.java:117)
    at org.springframework.boot.loader.ExecutableArchiveLauncher.<init>(ExecutableArchiveLauncher.java:38)
    at org.springframework.boot.loader.JarLauncher.<init>(JarLauncher.java:35)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
    at com.oracle.svm.reflect.proxies.Proxy_1_JarLauncher_main.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.oracle.svm.core.JavaMainWrapper.run(JavaMainWrapper.java:199)
    at Lcom/oracle/svm/core/code/CEntryPointCallStubs;.com_002eoracle_002esvm_002ecore_002eJavaMainWrapper_002erun_0028int_002corg_002egraalvm_002enativeimage_002ec_002etype_002eCCharPointerPointer_0029(generated:0)

Error: Processing image build request failed

今度はjava.lang.ClassLoaderを生成できないと怒られた。

どうやらnative-imageではSpringのように動的にクラスをロードする仕組みはサポートしていない(できない)らしい。
https://github.com/oracle/graal/blob/master/substratevm/LIMITATIONS.md

Hibernateとか他のORマッパーも普通は動的なクラスローディングでインスタンスを生成しているはずなので、ほとんどのフレームワークで使えないな。

VM上での実行は普通にできるので、native-imageを使わなければユニバーサルVMという概念は達成できるかもしれない。(本当にできるとは思ってないけど)

55
26
0

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
55
26