Graal VM 알아보기 (차세대 Java VM)
이번에 K-DEVCON 대전에서 연말을 맞아 행사를 진행했었다. (관련 post)
나는 이번 행사에서 Java 8부터 21까지: 자바 주요 변화 알아보기 라는 제목으로 발표를 진행하였는데, Graal VM 에 대해서도 이야기 할 수 있는 기회가 있었다.
이번 글을 통해서는 발표를 준비하면서 알게 된 Graal VM 이 기존의 JVM 과 어떤 점이 다른지에 대해서 설명하고자 한다.
Graal VM
기존의 Java VM
Write Once, Run Anywhere 한 번 작성해서 어디서나 실행
자바의 표어이다. 당시에는 매우 매력적인 표어였다고 한다. 이 부분은 플랫폼 독립성을 뜻하는데 이를 제공하기 위해 JVM (Java Virtual Machine) 이 핵심역할을 한다. (플랫폼 독립성: 운영 체제와 관계없이 동일하게 바이트코드를 실행할 수 있음)
JVM은 자바 바이트코드를 실행하는 가상 머신이다. JVM 을 통해서 Java Application 을 어디서든 실행시킬 수 있다.
개발자가 작성한 .java 파일은 javac 를 거처 .class 파일에 바이트 코드로 저장된다. 저장된 바이트 코드는 jvm에 의해 로드되어 해석(인터프리트)된다. 최적화 될 수 있는 부분은 jvm 에서 JIT 컴파일러를 통해서 머신 코드(기계어)로 변경한다.
이미지 출처 : well-grounded java developer
JVM을 통한 플랫폼 동립성은 자바의 장점이였지만, 속도가 중요한 환경에서는 한계가 존재했다.
Graal VM
Graal VM 은 이러한 문제를 해결해 줄 수 있는 솔루션이다.
Graal VM 은 Oracle 에서 만들고 있는 차세대 JVM 이다. 공식 홈페이지 에서는 다음과 같은 표어를 사용하여 Graal VM 을 소개하고 있다.
Build faster, smaller, leaner applications An advanced JDK with ahead-of-time Native Image compilation
번역해보면 다음과 같다.
더 빠르고, 더 작고, 더 간결한 애플리케이션 빌드 사전 네이티브 이미지 컴파일 기능을 갖춘 고급 JDK
Graal VM도 Java SE 표준을 준수하기 때문에 기존의 Java 애플리케이션 대부분을 실행할 수 있다고 한다.
Graal VM 의 주요 기능
Graal VM 의 주요 기능 2가지는 다음과 같다.
- Native Image
- Polyglot Programming (multi language runtime)
각각에 대해서 예시와 함께 좀 더 알아보도록 하자.
Native Image
Native Image 는 사전(ahead-of-time, aot) 컴파일된 네이티브 이미지를 의미한다.
동작 방식
애플리케이션 코드를 컴파일 타임에 네이티브 코드로 변환하여 사용할 수 있도록 한다. 이를 통해 기존에 자바가 가지고 있었던 속도 문제를 해결할 수 있게 되었다.
바이트코드를 네이티브 코드로 변환한다.
기존 JVM 기반 어플리케이션 과의 주요 차이점
GraalVM 네이티브 이미지는 사전에 생성된다. 이로 인해 기존의 JVM 기반 어플리케이션과 몇 가지 차이점들이 있게 된다. 주요 차이점은 다음과 같이 정리해볼 수 있다.
- 애플리케이션의 정적 분석은 main 진입점에서 빌드 시점에 수행된다.
- 네이티브 이미지가 생성될 때 접근할 수 없는 코드는 제거한다.
- GraalVM은 코드의 동적 요소를 직접 인식하지 못하며 리플렉션, 리소스, 직렬화 및 동적 프록시 등에 대해 빌드시에 알려야 한다. (hint를 줘야 한다.)
- 애플리케이션 classpth는 빌드 시점에 고정되며 변경할 수 없다.
- 지연된 클래스 로딩은 없으며, 실행 파일에 포함된 모든 내용은 시작 시 메모리에 로드된다.
- 적절히 힌트를 주면 대부분 해결 가능하긴 하지만 Java 애플리케이션의 일부 측면에서 완전히 지원되지 않는 몇 가지 제한 사항이 있을 수 있다.
Spring 과의 호환성
기존에는 spring native 라는 별도 프로젝트로 관리되고 있다가 Spring Boot 3 부터는 자체적으로 Graal VM 과 사용할 수 있도록 통합되었다. 더 자세한 내용은 spring-boot doc 의 native-image 파트 에서 잘 설명해주고 있다.
사용해보기
우선 javac
로 컴파일을 진행하여 class 파일을 만든 후 native-image
를 만든다.
생성이 완료되면 다음과 같이 실행파일이 생긴다. 해당 파일을 실행시키면 java application 이 실행된다.
요약
native image의 장점과 단점은 다음과 같이 정리해볼 수 있을 것 같다.
- 장점
- 실행 환경에서 JVM이 없어도 실행 가능하다.
- 컴파일 된 실행파일이기 때문에 실행 속도가 기존 대비 엄청 빠르다.
- 용량도 경량화 할 수 있다.
- 단점 :
- 동적으로 런타임에 실행되던 부분들에서 이슈가 생긴다. (reflect, proxy 등)
- 힌트를 통해 대부분 해결 가능하다.
- 플랫폼 종속성이 생긴다. 실행이 필요한 플랫폼에 맞게 빌드를 진행해야 한다.
- 동적으로 런타임에 실행되던 부분들에서 이슈가 생긴다. (reflect, proxy 등)
Polyglot Programming (multi language runtime)
Graal VM 은 자체 인터프리터(Truffle)를 통해 다중 언어 런타임을 제공한다. 이를 기반으로 Graal VM 런타임에서는 다양한 언어들을 통합하여 실행할 수 있다.
지원 언어
javascript, python 등 다양한 언어들을 제공한다.
사용해보기
graal-sdk, truffle-api 와 함께 사용하고자 하는 언어에 대한 dependency를 추가해준다.
다른 언어의 코드를 실행시켜 자바에 통합한 것을 볼 수 있다. (따로 세팅 없이 한거라 warning이 많이 보이긴 하지만)
자체 인터프리터를 사용하기 때문에, 별도의 환경 세팅을 하지 않더라도 문제없이 다른 언어를 실행시킨다.
어디에 사용할까?
처음에는 굳이 다른 언어를 JVM 위에서 실행시킬 필요가 있을까 생각하였다. 하지만 다음과 같은 장점을 얻을 수 있을 것 같다.
한 언어에서 다른 언어로의 상호 운용성이 생기게 된다. Java 에서 다른 언어의 코드를 호출할 수 있고, 또 반대로 다른 언어에서 Java 의 데이터에 접근할 수 있다. 서로 직접 상호 작용하고 동일한 메모리 공간에서 데이터를 주고받을 수 있다. 이를 통해 별도의 외부 통신 수단(예: HTTP API, 메시지 큐 등)을 사용하지 않고도 언어 간의 경계를 허물 수 있다.
좀 더 구체적인 예시를 들어보면 다음과 같을 것이다.
- Java 애플리케이션에 Python 기반의 AI 모델을 통합한다.
- Java 애플리케이션에 Python의 NumPy 라이브러리를 사용한 복잡한 수학 계산 처리를 진행한다.
- react.js 와 Java 백엔드 을 함께 통합하여 운영
마무리
말로만 듣던 Graal VM 에 대해서 이번 발표를 준비하면서 알아볼 수 있었다. 자바 생태계는 자바를 더욱 경량화하고 최적화될 수 있는 방법을 만들어 나가고 있다. 앞으로의 자바 생태계도 어떻게 될지 기대된다.