자바 가상 머신

1. 개요
2. 종류
3. 구조
4. 성능
4.1. 가비지 컬렉션 (GC)
5. JVM 기반 언어
5.1. 기존 언어의 JVM 구현
5.2. JVM 기반의 언어
5.3. 관련 문서
6. 관련 문서

1. 개요

Java로 개발한 프로그램을 컴파일하여 만들어지는 바이트코드를 실행시키기 위한 가상머신. JRE(Java Runtime Environment)에 포함되어 있으며, Java 컴파일러가 프론트엔드를 담당한다면 Java 가상 머신은 코드 최적화와 백엔드를 담당한다. Java와 함께 썬 마이크로시스템즈에서 개발되었으며 썬이 오라클에 인수된 후 현재는 오라클이 Java 명칭을 비롯하여 모든 권한을 행사하고 있다. Java 소스 코드는 javac 컴파일러를 거쳐 바이트코드로 변환되며, 이 바이트코드는 JRE에 들어있는 java classloader에 의해 JVM으로 적재되고 JVM은 적재된 바이트코드를 JIT 컴파일 방식으로 실행한다.

JVM은 플랫폼 독립적으로, JVM이 실행 가능한 환경이라면 어디서든 Java 프로그램이 실행될 수 있도록 한다. 즉, Java의 모토인 Write once, RunTest anywhere는 JVM을 통해 가능한 것이다. 하지만 특정 운영체제의 특수한 기능을 호출하거나 하드웨어를 제어하는 등의 일은 JVM으로 할 수 없으며, JNI 같은 Native 코드를 호출하기 위한 인터페이스를 거쳐야 한다. 즉 일종의 샌드박스 환경인 셈.

Java 가상머신이라고 해서 Java 바이트코드만 인식하는 것은 아니다. 이 바이트코드를 Java가 아닌 다른 언어들[1]을 가지고도 생성할 수 있기 때문이다. 따라서 지금의 Java 가상머신은 Java만을 위한 것이라고 생각하면 안 된다. 이름이 Java 가상머신이다 보니 Java에 종속된 게 아닌가 생각할 수도 있지만 그렇지도 않다. Java 가상머신은 코틀린 코드를 컴파일해도 읽을 수도 있고 스칼라 코드를 컴파일해도 읽을 수 있다. 단, 기본이 Java를 위해서 만들어졌기 때문에 Java 소스 코드와 컴파일된 바이트코드는 비교적 직관적으로 연결되지만, 코틀린이나 스칼라의 경우 Java와의 호환성을 고려하긴 했어도 상대적으로는 비직관적이며 필연적으로 Java를 공부해야 한다는 단점이 있다.

.NET Framework와 함께 가상머신 언어 시장을 사실상 양분하고 있다.

2. 종류

오라클이 소유한 두 종류의 JVM으로 썬 마이크로시스템즈에서 개발된 HotSpot과 BEA 시스템에서 개발된 JRockit, IBM J9을 기반으로 한 Eclipse OpenJ9이 있다, 클린 룸 구현에는 KafeeIBM사의 IBM J9가 있다. 윈도우, 리눅스 등의 환경에서는 대부분 HotSpot이 사용되지만, IBM AIX를 운영체제로 사용하는 경우 IBM J9가 널리 사용된다.

구글안드로이드는 Java를 사용하여 개발되었지만, 안드로이드에 있는 달빅 가상 머신은 Java 바이트코드를 전혀 실행하지 못하므로 엄밀하게 말하면 JVM은 아니다. 다만 Java 바이트코드를 한 번 변환해서 달빅용 코드로 만들고 그걸 실행한다. 좀 바보같긴 하지만, JVM을 포함한 Java의 여러 부분에 걸린 특허를 피하기 위해 내놓은 꼼수. 다만 결국 썬을 인수한 오라클이 이 문제로 소송을 걸었다. 안드로이드가 잘 나가는 걸 본 썬은 독립 회사였을 때 재주는 썬이 넘고 돈은 구글이 벌어서 배는 무지 아팠지만 공돌이의 정으로 참고 있었다고 한다. 구글이나 썬은 공돌이 회사의 대표격이었으니...반면 오라클은 문화적으로 봤을 때 전통적인 양복 회사에 가까워서 그딴 건 상관 없었던 모양. 결국 속도 문제[2]도 해결할 겸 구글은 달빅을 포기하고 안드로이드 런타임으로 변경했다.

마이크로소프트에서도 JVM을 내놓은 적이 있었다. Java Applet 실행을 위해 Internet Explorer 버전 3부터 제공했다고. 이후 1997년 썬에게 고소크리를 먹게 된다. 오라클마냥 돈 문제는 아니고, MS가 Java 1.1 표준을 무시한 채 자신들 입맛대로 뜯어고쳤기 때문이다.[3] 결국 2001년부터 개발과 배포를 중단했다.

3. 구조

4. 성능

바이트코드는 실제의 기계에서 직접 실행되는 것이 아니라 JVM의 해석 단계를 거쳐 실행되므로 Java로 개발된 프로그램은 같은 기능의 네이티브 언어[4]보다 실행 속도가 느리다. 과거에는 바이트코드를 순수하게 인터프리트하여 매우 느렸으나 현재는 JIT 컴파일의 도입과 하드웨어의 발전으로 눈꼽만큼 성능이 개선되었다.

JVM은 추상적인 머신이며, 메모리의 접근을 가상 머신 차원에서 관리하고 있으므로 런타임에 최적화가 가능하다. 매우 극단적이고 특수한 상황을 가정하면 극히 일부 기능에 대해서는 네이티브 언어보다 더 우월한 성능을 보여 주기도 한다. 하지만 JIT 컴파일 시간, 가비지 컬렉션을 위한 시간 등이 필요하므로 근본적인 한계가 있다.[5]

4.1. 가비지 컬렉션 (GC)

JVM은 가비지 컬렉션을 수행하여 할당되었다가 더 이상 쓰이지 않는 메모리를 자동으로 회수한다. Full GC(전체 가비지 컬렉션)의 경우 프로그램 수행을 일시 정지(Stop-the-World) 시켜놓고 할 수밖에 없는데, 또 이게 Java 프로그램이 규칙적이지도 않고 이유도 없이 뚝뚝 끊긴다는 악명을 떨치는데 공헌했다. 대규모 서비스의 운영 시 Full GC는 성능에 상당히 심각한 영향을 주므로 프로그래머의 GC 튜닝이 필수로 들어간다. 최신 버전(11~12 이후)의 JVM에는 힙의 크기와 상관없이(수백 MB ~ 수십 TB까지) 일시정지 시간이 10ms 이하인 GC 알고리즘들(ZGC, Shenandoah)이 탑재되어 있다.

JVM 모니터링 클라이언트 VisualVM[6]과 그 플러그인 Visual GC를 설치하면 가비지 컬렉팅 상황을 시각적으로 확인할 수 있다. # VisualVM 디렉토리의 etc 폴더에 가면 visualvm.conf라는 파일이 있는데, 이 파일에 적혀 있는 visualvm_jdkhome 항목의 주석(#)을 제거한 후 JDK 폴더의 경로를 적으면 자신이 원하는 버전의 JDK로 모니터링이 가능하다.

GC의 상세한 동작 과정에 대해서는 이 문서를 참고할 것.

5. JVM 기반 언어

이름에 Java가 들어 있지만 JVM은 자신이 무슨 언어를 실행하는지 전혀 관심이 없다. 형식만 올바로 지켜서 만들어졌다면 Java가 아니라 Java 바이트코드를 만드는 다른 언어도 얼마든지 실행할 수 있는 것.

JVM의 플랫폼 독립성과 준수한 성능, 그리고 Java 코드와의 손쉬운 상호작용 등의 특징으로 인하여 JVM을 기반으로 하는 Java 이외의 언어들도 많이 개발되어 있다.

5.1. 기존 언어의 JVM 구현

5.2. JVM 기반의 언어

5.3. 관련 문서

6. 관련 문서


  1. [1] Kotlin이나 Scala, Groovy 같은 언어들
  2. [2] 달빅은 JIT라고는 해도 상술한 문제로 인해 속도가 느릴 수밖에 없다.
  3. [3] MS의 이러한 행보에는 의도적인 비호환성을 통해 결국 Java의 발목을 잡게 하려는 꼼수가 있었다는 지적이 많았다.
  4. [4] C, C++, Rust, Go
  5. [5] 이 부분이 매우 중요해서 JVM이나 .NET CLR 등 가상머신 기반에서 벤치마크를 돌릴 때는 1~5회 정도 웜업을 한 후에 측정한다.
  6. [6] 넷빈즈를 기반으로 만들어져 있다.

최종 확인 버전:

cc by-nc-sa 2.0 kr

Contents from Namu Wiki

Contact - 미러 (Namu)는 나무 위키의 표가 깨지는게 안타까워 만들어진 사이트입니다. (45.10ms)