Graalvm Native Image 시작하기

Marvin Kim (Hong-IL)
9 min readJul 17, 2023

--

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과 같은 도구를 이용하여 열 수 있습니다.

관련하여 좀 더 자세한 내용은 아래 링크를 참고해 주시기 바랍니다.

Getting Started — Native Images

Reference Manual — GraalVM Native Image

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Marvin Kim (Hong-IL)
Marvin Kim (Hong-IL)

No responses yet

Write a response