Compiled 언어 vs Interpreted 언어
우리가 작성한 코드가 실행이 되기 위해선 각 Target OS 에 맞는 기계어로 번역이 되야합니다.
컴파일 언어는 모든 코드를 한번에 기계어로 바꾸는 언어이고,
인터프리터 언어는 프로그램을 실행하는 도중 코드를 줄별로 변환하여 실행하는 언어입니다.
그럼 장단점이 명확해집니다.
- Compile : 프로그램을 빌드하는 시간이 오래걸리는 대신 모두 기계어로 변환되어 있기 때문에 실행속도는 상대적으로 빠릅니다.
- 하지만 코드가 조금만 변경된다면 전체를 재 빌드해야합니다.
- Interprete : 프로그램을 빌드하는 시간이 짧은대신 실제 프로그램이 실행할 때 상대적으로 느립니다.
- 하지만 코드가 수정되었을 때 전체를 빌드할 필요가 없습니다.
- 또한 Byte Code 와 Machine Code 는 메모리를 차지하는 용량이 정말 많이 차이납니다. 따라서 메모리 최적화를 위해서라면 Byte Code가 훨씬 유리합니다.
Spring 과 Node 를 둘다 사용해보신 분들이라면 아시겠지만, Spring 은 코드가 변하면 재실행을 시켜야하지만 Node는 재실행을 시키지않아도 코드가 자동으로 적용됩니다. 아마도 IDE에서 이런부분 고려하여 기능을 지원해주지 않았을까 싶습니다.
Java는 인터프리터 언어라던데?
맞는말이죠. 하지만 인터프리터 언어이기도하고 컴파일언어이기도 합니다.
우리가 작성한 자바코드는 먼저 javac라는 컴파일러를 통해 ByteCode 로 컴파일됩니다. 여기서 일반적인 컴파일언어와는 다르게 바로 기계어로 번역하는게 아닌 JVM이 원하는 Byte 코드로 번역하여 JVM 메모리에 올리게됩니다.
그 후, JVM 이 Target OS에 맞춰 기계어로 번역하는 것이죠.
이 과정을 유심히 생각해보면 Compiled 언어와 interpreter 언어의 단점을 둘다 가지고있는게 보입니다.
그래서 자바는 타언어에 비해 성능이 좋지않다라는 소리를 듣는 것이죠.
하지만 JVM 을 사용함으로써 어떤 OS 던간에 호환성을 가져갈 수 있다는 장점이 있긴합니다.
JIT Compiler
Jit Compiler 의 J는 Java가 아닌 Just 입니다. JIT 은 Just-in-Compile 의 약자로 Compile 방식과 Interpret 방식에 만족하지 못했던 개발자들이 각각의 장점만 뽑아내 만들어낸 방식입니다.
JIT 컴파일러는 애플리케이션이 실행되는 런타임에 동작합니다. (Just-in-Compile의 의미)
JVM이 Byte 코드를 기계어로 해석하여 즉시 실행을 하는 시점에 특정 Byte 코드가 자주 실행된다 판단이 되면 이를 기계어로 변환하여 캐시에 저장하여 추후 해당 코드가 실행되어도 해석하지 않게 합니다.
따라서 Byte 코드로 가지고있어 메모리에 최적화 되어있지만 자주사용하는 코드는 캐싱하여 빠른 실행속도를 가져가는 방식입니다.
AOT Compiler
AOT는 Ahead-of-Time 의 약자로 프로그램을 실행하기 전, 소스 코드를 모두 기계어로 변환하여 실행하는 방식입니다. 따라서 실제 실행을 할 때 기계어로 변환된 코드를 실행하게됩니다.
이는 애플리케이션의 시작 시간을 단축시키고, 런타임 환경에서 실행속도 개선에 도움을 줍니다.
Compiler 내용과 이어지는 GraalVM
아래는 Oracle에서 제공하는 GraalVM 아키텍쳐입니다.
아래 그림에서 Graal Compiler란 자바로 작성된 동적 JIT(Just-In-Time) 컴파일러로, 자바 바이트코드를 머신 코드로 변환하는 역할을 합니다.
GraalVM에서 AOT Compiler는 네이티브 이미지(Native Image)를 지원해 자바와 JVM 기반 코드를 네이티브 실행 파일로 변환할 수 있습니다. 이 네이티브 실행 파일은 빠르게 시작되며, 적은 리소스를 사용하기 때문에 클라우드 환경에 적합합니다.
JVM 은 인터프리터 언어와는 다르게 StartUp되는 시간이 너무 길었는데요. AOT Compiler가 해결해준 모습입니다.
GraalVM 사용시 주의할 점
GraalVM을 사용하면 단지 VM만을 바꾼다는 이유로 빠른 시작, 적은 리소스사용, 폴리그랏 프로그래밍지원 이라는 장점을 가져옵니다.
하지만 기존 JDK 환경에서 동작하던 스프링의 모든 의존성이 Native 빌딩 과정에서 안되는 경우가 있습니다.
또한, AOT 의 경우 동적요소들 Reflection, Dynamic Proxy 등을 처리할 수 없습니다.
예시로는 @Profile 과 Mockito 를 사용할 수 없습니다.
'Java' 카테고리의 다른 글
[Java] 멀티스레드와 동시성 (0) | 2024.09.14 |
---|---|
[Java] Wrapper (0) | 2023.03.15 |
[Java] Optional (0) | 2023.03.15 |
[Java] 메모리 영역과 Garbage Collection (0) | 2023.03.14 |
[Java] JRE, JDK, JVM (0) | 2023.03.14 |