직역하면 '자바를 실행하기 위한 가상 기계(컴퓨터)'라고 할 수 있다.
Java 는 OS에 종속적이지 않다는 특징을 가지고 있다. OS에 종속받지 않고 실행되기 위해선 OS 위에서 Java 를 실행시킬 무언가가 필요하다. 그게 바로 JVM이다.
즉, OS에 종속받지 않고 CPU 가 Java를 인식, 실행할 수 있게 하는 가상 컴퓨터이다.
Java 소스코드, 즉 원시코드(*.java
)는 CPU가 인식을 하지 못하므로 기계어로 컴파일을 해줘야한다.
하지만 Java는 이 JVM 이라는 가상머신을 거쳐서 OS에 도달하기 때문에 OS가 인식할 수 있는 기계어로 바로(한번에) 컴파일 되는게 아니라 JVM이 인식할 수 있는 Java bytecode(*.class
)로 변환된다.
Java compiler 가 .java
파일을 .class
라는 Java bytecode로 변환한다.
여기서 Java compiler 는 JDK를 설치하면 bin 에 존재하는 javac.exe를 말한다. (즉, JDK에 Java compiler가 포함되어 있다는 소리임) javac 명령어를 통해 .java를 .class로 컴파일 할 수 있다.
변환된 bytecode는 기계어가 아니기 때문에 OS에서 바로 실행되지 않는다.
이 때, JVM이 OS가 bytecode를 이해할 수 있도록 해석해준다. 따라서 Byte Code는 JVM 위에서 OS 상관없이 실행될 수 있는 것이다.
즉 JAVA는 OS에 종속적이지 않고, Java 파일 하나만 만들면 어느 디바이스든 JVM 위에서 실행할 수 있다.
Java Compiler는 JDK를 설치하면 javac.exe라는 실행 파일 형태로 설치된다. 정확히는 JDK 의 bin 폴더에 javac.exe 로 존재한다.
Java Complier 의 javac
라는 명령어를 사용하면 .class 파일을 생성할 수 있다.
Mac Terminal에서 컴파일하는 방법은 다음과 같다
javac *.java
명령어로 컴파일java *파일명
으로 실행자바 바이트 코드(Java bytecode)는 JVM이 이해할 수 있는 언어로 변환된 자바 소스코드를 의미한다.
자바 컴파일러에 의해 변환된 코드의 명령어 크기가 1바이트라서 자바 바이트 코드라고 불리고 있다.
바이트 코드는 다시 실시간 번역기 또는 JIT 컴파일러에 의해 바이너리 코드로 변환된다.
🦭 Java Source code 변환 과정
소스코드 → [ 🏭 자바 컴파일러 ] → 바이트 코드(JVM이 이해 가능) → [ 🏭 실시간 번역기 or JIT 컴파일러 ] → 바이너리 코드(OS가 이해 가능)
JIT 컴파일러(just-in-time compliation)는 프로그램을 실제 실행하는 시점에 기계어로 번역하는 컴파일러이다.
JIT 컴파일(just-in-time compliation)은 동적 번역(dynamic translation) 이라고도 한다.
인터프리터 방식의 단점을 보완하기 위해 도입되었다.
인터프리터 방식으로 실행하다가 적절한 시점에 바이트 코드 전체를 컴파일하여 기계어로 변경하고, 이후에는 해당 더 이상 인터프리팅 하지 않고 기계어로 직접 실행하는 방식이다.
기계어(컴파일된 코드)는 캐시에 보관하기 때문에 한 번 컴파일된 코드는 빠르게 수행하게 된다. 물론 JIT 컴파일러가 컴파일하는 과정(먼저 인터프리팅하다가 일정 시점에서 진행하는 컴파일 과정을 말함)은 바이트 코드를 그냥 인터프리팅하는 것보다 훨씬 오래걸리므로 한 번만 실행되는 코드라면 컴파일 하지 않고 인터프리팅하는 것이 유리하다.
따라서 JIT 컴파일러를 사용하는 JVM들은 내부적으로 해당 메서드가 얼마나 자주 수행되는지 체크하고 일정 정도를 넣을때에만 컴파일을 수행한다.