Graalvm Native Image 시작하기
Graalvm Native Image
Java VM 내에서 애플리케이션을 실행하면 시작 시간 및 메모리 등의 비용이 발생합니다.. Graalvm에는 기존 JVM 기반 응용 프로그램의 기본 이미지를 생성하는 기능이 있습니다. Java 코드를 정적 분석하여, AOT (Ahead-of-Time) 컴파일을 수행하여 Native Image 라는 독립적으로 실행이 가능한 바이너리 파일로 만들고 이 프로그램은 머신에서 즉시 실행됩니다. 이 실행 파일에는 다음이 포함되어 있습니다.
- 애플리케이션 클래스
- 실행에 필요한 다른 클래스
- JDK 런타임 라이브러리
- JDK와 정적으로 링크된 native code
- Substrate VM
Substrate VM은 Java VM이 담당하던, 메모리 관리 및 스레드 스케줄링을 담당합니다.
Native Image 만드는 방법
Native Image Generator 또는 native-image 는 JDK의 클래스를 포함하여 애플리케이션의 모든 클래스와 해당 종속성을 처리하는 유틸리티입니다.
Native Image에서 지원되는 언어는 Java, Scala, Clojure, Kotlin과 같은 JVM 기반 언어이며, JavaScript, Ruby, R 또는 Python의 경우 실행할 수는 있으나 컴파일하지는 않는다. Polyglot의 경우, — language:<languageId> 옵션을 이용해, 게스트 언어를 전달해 줍니다.
Native Image 설치에 앞서
Native Image 설치에 앞서, glibc-devel, zlib-devel(C 라이브러리의 헤더 파일 및 zlib) gcc이 시스템에서 사용 가능한지 확인하십시오.
Linux 플랫폼의 경우 libstdc++ 종속성을 추가로 설치하시기 바랍니다.
Native Image 설치
Graalvm EE 시작하기에서 다운로드 받은 바이너리 중, Oracle Graalvm Enterprise Edition Core를 압축해제하고, 아래와 같이 GraalVM 홈 디렉토리를 GRAALVM_HOME으로 지정하고 PATH에 $GRAALVM_HOME\bin을 PATH에 추가하세요.
export GRAALVM_HOME=/home/${current_user}/path/to/graalvm
해당 bin 폴더에는 gu (Graalvm Updater) 라는 실행파일이 있고, 아래와 같은 명령어를 통해 native image plugin을 설치해 줍니다.
gu -L install native-image-installable-svm-svmee-java8-linux-amd64-20.1.0
자, 이제 native-image를 실행할 준비가 되어 있습니다.
Native Image 데모 설치
아래 저장소를 다운로드하거나 복제하고 native-list-dir 디렉토리로 이동합니다.
git clone https://github.com/graalvm/graalvm-demos
cd graalvm-demos/native-list-dir
사용자의 편의를 위해 build.sh 에는 java 코드를 컴파일하고, native-image 명령어를 실행하는 코드가 들어 있습니다.
build.sh를 실행하여 native image를 만듭니다.
./build.sh
build.sh의 내부를 살펴보면, 아래와 같이
$GRAALVM_HOME/bin/native-image ListDir
native-image 명령어를 이용해 ListDir 클래스를 native image로 만듭니다.
명령을 실행한 후 실행 파일 listdir이 생성됩니다.
Native Image 실행
run.sh는 아래와 같이 java 명령어를 이용해서 ListDir 클래스를 실행하는 명령어와 native image를 실행하는 명령어가 차례로 실행이 됩니다.
time java ListDir $1 time ./listdir $1
아래와 같이 폴더를 인자로 제공하면 다음과 같이 결과가 출력이 됩니다.
$ ./run.sh
+ java ListDir ..
Walking path: ..
Total: 141 files, total size = 14448801 bytes
real 0m0.320s
user 0m0.379s
sys 0m0.070s
+ ./listDir ..
Walking path: ..
Total: 141 files, total size = 14448801 bytes
real 0m0.030s
user 0m0.005s
sys 0m0.011s
이를 통해, native image를 이용한 시간이 java class를 실행한 시간 보다 훨씬 짧음을 보실 수 있습니다.
native-image 옵션
native-image의 옵션은 java에서 익숙하게 사용되던 옵션들을 사용하여 클래스들에 대한 경로를제공해 줍니다.
-cp 옵션 다음으로 :으로 분리된 경로와 jar파일들 리스트를 넣고, 마지막에 main 메소드를 포함한 클래스명을 넣거나, -jar 옵션이후 main 메소드를 포함한 manifest를 담은 jar파일명을 제공해 줍니다.
native-image –help를 이용해 옵션들의 개요를 얻고, native-image — help-extra를 이용해 비표준 옵션에 대한 도움말을 확인하세요.
Native Image에서 힙 덤프 하기
Native Image는 JVMTI 에이전트를 구현하지 않기 때문에, VisualVM 또는 jmap 과 같은 도구를 사용하여 힙 덤프를 할 수 없습니다.
애플리케이션이 특정 신호를 처리할 수 있도록 구현하고, 애플리케이션이 USR1신호를 수신할 때 힙 덤프를 얻는 방식으로 애플리케이션의 이미지를 빌드 할 수 있습니다.
Native Image에는 H:+AllowVMInspection 옵션을 넣어야 합니다.
다음 Java 예제는 60초 동안 실행되는 간단한 다중 스레드 애플리케이션입니다.
PID를 가져와서 SIGUSR1 신호를 전송하여 애플리케이션의 작업 디렉토리에 힙 덤프를 생성하도록 요구할 것입니다.
다음 코드를 디스크에 SVMHeapDump.java 파일로 저장하세요.
다음과 같이 SVMHeapDump.java를 컴파일하세요.
$JAVA_HOME/bin/javac SVMHeapDump.java
이제 실행하면 60 초 동안 실행된 다음 완료됩니다.
이제 native-image가 SIGUSR1 신호를 받아 힙 덤프를 생성하는 native image를 생성하는 방법을 살펴 보겠습니다.
native-image 명령어에 아래와 같이 -H:+AllowVMInspection 옵션을 넣어 native image를 생성합니다.
$ $JAVA_HOME/bin/native-image SVMHeapDump -H:+AllowVMInspection
Build on Server(pid: 41691, port: 61250)
[svmheapdump:41691] classlist: 412.03 ms, 2.52 GB
[svmheapdump:41691] (cap): 1,655.34 ms, 2.52 GB
[svmheapdump:41691] setup: 2,741.18 ms, 2.52 GB
[svmheapdump:41691] (clinit): 190.08 ms, 2.59 GB
[svmheapdump:41691] (typeflow): 5,231.29 ms, 2.59 GB
[svmheapdump:41691] (objects): 6,489.13 ms, 2.59 GB
[svmheapdump:41691] (features): 203.11 ms, 2.59 GB
[svmheapdump:41691] analysis: 12,394.98 ms, 2.59 GB
[svmheapdump:41691] universe: 425.55 ms, 2.59 GB
[svmheapdump:41691] (parse): 1,418.69 ms, 2.59 GB
[svmheapdump:41691] (inline): 1,289.94 ms, 2.59 GB
[svmheapdump:41691] (compile): 21,338.61 ms, 2.62 GB
[svmheapdump:41691] compile: 24,795.01 ms, 2.62 GB
[svmheapdump:41691] image: 1,446.14 ms, 2.62 GB
[svmheapdump:41691] write: 5,482.12 ms, 2.62 GB
[svmheapdump:41691]
[total]: 47,805.47 ms, 2.62 GB
이 native-image 명령어는 SVMHeapDump.class 파일을 분석하고 실행 파일을 작성합니다. 명령이 완료되면 svmheapdump가 현재 디렉토리에 저장됩니다.
svmheapdump를 실행하세요.
$ ./svmheapdump
May 15, 2020, 4:28:14 PM: Hello GraalVM native image developer!
Get PID of this process: 'ps -C svmheapdump -o pid= '
then send it signal: 'kill -SIGUSR1 pid'
to get heap dump generated into working directory.
Starting thread!
May 15, 2020, 4:28:14 PM: Thread started, it will run for 60 second
다른 터미널을 열어 “ps -svmheapdump -o pid= “를 입력해서 pid를 얻고, 해당 pid를 다음 명령에 넣어 애플리케이션을 중지하면, 힙 덤프가 자동으로 이루어집니다.
kill -SIGUSR1 pid
생성된 힙 덤프는 다른 Java 힙 덤프와 같이 VisualVM과 같은 도구를 이용하여 열 수 있습니다.
관련하여 좀 더 자세한 내용은 아래 링크를 참고해 주시기 바랍니다.