들어가기 앞서
최근 JVM을 보완하는 새로운 가상머신이 개발되었고 생각보다 많은 서비스에서 사용중이라는 소식을 들었다.
Java는 다른 컴파일러 언어에 비해 느리다는 이야기를 들었고, 그 원인이 JVM에서 비롯되었다고 익히 알고 있던 와중 보완된 JVM을 통해 Java의 성능 문제를 해결할 수 있다는 사실에 흥미를 가지고 살펴 보았다.
기존 JVM의 한계
사실 Java의 시작을 함께한 JVM을 대체하기 위한 시도는 과거에도 빈번했다.
C, C++, Golang과 같은 컴파일러 기반의 언어는 컴파일 과정에서 바로 기계어로 번역되고 실행 파일을 만들어낸다. 그리고 컴파일 시에 코드 최적화까지 진행하여 인터프리터 대비 뛰어난 성능을 가지고 있다.
반면, Java는 플랫폼 종속적인 문제를 해결하기 위해 인터프리터(Interpreter) 방식을 사용하고 있고, Java 코드가 바이트 코드로 변환 후 기계어로 번역되는 과정으로인해 컴파일러 방식에 비해 플랫폼 독립성은 보장되지만 실행 속도가 느려지는 단점이 있다.
이후 Java는 인터프리터 방식의 성능 이슈를 해결하기 위해서 Java 1.1 버전부터 부분적으로 JIT 컴파일러를 도입하였고, Jav 1.2 버전부터 자주 실행되는 코드를 식별 할 수 있는 HotSpot JVM을 도입하면서 JIT Compiler의 시너지로 Java 성능을 크게 향상 시킬 수 있었다.
* JIT 컴파일러는 C1, C2 컴파일러로 구성되어 있으며 단계별 컴파일(Tiered Compile) 과정을 거치며 코드를 최적화 한다.
그럼에도 여전히 기존 JVM은 JIT 컴파일러의 웜업(WarmUp) 과정으로 인한 초기 실행 속도 이슈, GC로 인한 메모리 관리 이슈등이 잔조하고 있으며, Kotlin Java 언어에서만 동작한다는 한계가 존재한다. 또한 C2 JIT 컴파일러는 엄청난 양의 코드와 매우 복잡한 구조로 있어 현 시점에서 해당 컴파일러의 유지보수가 어렵고 이로 인해 새로운 최적화 기법을 적용하거나 기존 코드의 변경에 많은 시간이 소요되는 딜레마에 직면했다.
결과적으로 기존 JVM이 가지는 근본적인 성능 문제를 해결하고, 더 다양한 언어를 지원할 수 있으며, 유지보수가 쉬운 JVM이 필요한 배경을 가지고 GraalVM이 개발되었다.
GraalVM 이란?
GraalVM은 Oracle Labs에서 개발한 고성능 범용 프로그래밍 언어 및 런타임 환경이다.
기존 JVM의 한계를 극복하고자 개발되었으며, Java Kotlin 언어만을 지원했던 것과 달리 Java, Python, Ruby 등 20여 개의 언어를 지원하고 또한 JVM과 LLVM기반의 Native Image 기술을 이용하여 애플리케이션을 실행한다. 결과적으로 기존 JVM 보다 더 빠른 속도와 적은 메모리 사용량 그리고 높은 안정성, 보안성을 제공한다.
다음은 GraalVM 공식 사이트에서 알려주는 특징이다.
1. 낮은 리소스 사용량
네이티브 실행 파일은 JVM에 필요한 메모리와 CPU 리소스의 일부만 사용하므로 활용도가 높아지고 비용이 절감된다.
2. 향상된 보안
네이티브 실행 파일에는 애플리케이션에 필요한 클래스, 메서드, 필드만 포함되어 있으므로 공격 노출 영역이 줄어든다.
3.빠른 시작
미리 컴파일된 네이티비 실행 파일은 즉시 시작되며 최고의 성능으로 실행하기 위해 웜업이 필요하지 않다.
4. 컴팩트 패키징(Compact Packaging)
네이티비 실행 파일은 크기가 작고 다양한 연결 옵션을 제공하므로 최소한의 컨테이너 이미지로 쉽게 배포할 수 있다.
네이티브 이미지(Native Image)
GraalVM의 특징을 살펴보면 네이티브 이미지를 기반으로 한 특징을 자세히 설명하고 있다.
GraalVM의 네이티브 이미지는 GraalVM에서 도입된 AOT(Ahead-of-Time) Compiler를 통해 생성되는 빌드 결과물이다.
이 실행 파일은 JVM을 필요로 하지않으며, 이로인해 시작 속도가 매우 빠르고, 메모리 소비가 적다.
네이티비 이미지는 기존 대비 시작시간은 50배 더 빠르게, 메모리 사용량은 5배 더 적게 사용한다고 설명하고 있으며, 이런 특징은 잦은 배포가 이루어지는 MicroServices 환경에서 효율적으로 사용할 수 있다고 설명하고 있다.
GraalVM - Native Image의 한계
그렇다면 이렇게 좋은 네이티비 이미지는 기존의 모든 JVM을 대체할 정도로 만능일까?
기존 JVM 보다 50배나 빠르고, 5배나 더 효율적인 메모리 관리를 하는 GraalVM으로 기존 JVM을 모두 대체해야 할것 같은 생각이 들지만 GraalVM에도 명확한 한계가 존재한다.
제약사항 및 단점
1. 동적 기능 제한
자바의 리플렉션(Reflection), 다이나믹 프록시(Dynamic Proxy), 클래스 로딩(Class Loading) 같은 동적 기능 사용에 제약이 있다.
2. 빌드 시간
AOT 컴파일 과정을 통한 네이티브 이미지를 생성하는것은 기존 JIT 컴파일러에 비해 오랜 시간이 걸린다.
3. 디버깅 어려움
디버깅 및 프로파일링 도구가 JVM환경만큼 아직 성숙하지 않다.
GraalVM 네이티브 이미지는 JVM없이 실행되므로, 전통적인 Java 디버깅 도구가 작동하지 않는다.
JVM에서는 -Xdebug, -Xrunjdwp 옵션과 스택 트레이스를 통해 디버깅 기능을 제공하지만 네이티브 이미지는 AOT 컴파일로 인해 디버깅 가능한 런타임 메타데이터(클래스, 메서드 정보)가 손실될 수 있으며 네이티브 이미지에서 발생하는 오류는 스택 트레이스 정보가 간소화되어 원인 파악이 어렵다.
4. 특정 플랫폼 종속
네이티브 이미지는 특정 플랫폼(Linux, macOS, Windows)을 대상으로 생성되며, 생성된 바이너리는 다른 플랫폼에서 실행할 수 없다.
이는 GraalVM이 플랫폼에 특화된 네이티브 코드로 변환되기 때문이다.
5. 장기적인 최적화 성능 부족
AOT 컴파일러로 생성된 네이티브 이미지는 초기 JIT 컴파일러에 비해 훨씬 뛰어난 성능을 보인다. 이는 네이티브 이미지는 JIT 컴파일러와 비교하여 기계어로 번역되는 그 시점에 바로 최적화가 진행되기 때문이다. 하지만 시간이 지나고 요청이 지속적으로 처리 될수록 JIT 컴파일러가 더욱 뛰어난 성능을 보이게 되는데, 이는 애플리케이션을 실행하며 얻어낸 실행 환경 정보를 바탕으로 더욱 합리적인 최적화를 진행하기 때문이다. 즉 기존 JIT 컴파일러 생성 파일은 초기 실행은 느리지만 웜업(WarmUp) 과정을 거치면서 AOT 컴파일러에 비해 더욱 안정적인 성능 보인다.
마무리
기존 JVM을 보완하여 혁신적인 JVM이 나왔음이 분명하고, 이미 여러곳에서 도입하고 있다는 소식이 들리고 있다. 또한 머지 않아 GraalVM이 JVM 영역에서 많은 부분을 차지할 수 있겠다는 생각도 하였다. 다만 기존 JVM의 JIT 컴파일러가 가지는 분명한 장점이 있고, GraalVM 또한 아직 더 보완하고 자리잡아야 할 부분도 명확해 보였다.
Java 가 나온지 수십년이 지난 현 시점에 Java를 대체한다는 명목으로 다양한 언어가 나왔음에도 아직도 Java만이 가지는 넓은 커뮤니티와 같은 범용성 그리고 장점들로 인해 널리 사용되고 있듯, GraalVM 또한 기존 HotSpot, JIT 컴파일러와 비교하여 적용할 서비스와 주어진 환경에 맞추어 깊이 고민하고 테스트하며 사용해야 할 듯 하다.
https://www.graalvm.org/latest/introduction/
'Java' 카테고리의 다른 글
[Java] Java 원격 디버깅(Java Remote Debugging) (0) | 2025.01.08 |
---|---|
[Java] JVM Warm up - if(kakao)2022 (1) | 2024.11.11 |
[JAVA] 회원 시스템 분산 트랜잭션(JTA) 처리와 성능 이슈 해결 (1) | 2024.10.31 |