Java: A simple, object-oriented, distributed, interpreted, robust, secure, architecture neutral, portable, high-performance, multithreaded, and dynamic language
특징
GC(프로그램에서 사용되지 않는 메모리를 자동으로 회수하는 메모리 관리 기법)
과 JIT 컴파일러(프로그램 실행 시점에 byte를 기계어로 변환) 기능 때문에 실행 속도 느림(성능 저하)
.java
소스코드를 컴파일한 바이트코드(.class
)를 읽고, 검증, 실행함. 플랫폼마다 동일한 실행환경을 보장받음. 메모리 관리를 개발자가 아닌 Garbage Collector가 수행자바파일을 실행하기 위해서는 두 단계가 필요 (1) 컴파일 (2) 실행
Compiler는 javac.exe에 해당, Java VM은 java.exe에 해당
javac는 파일을 컴파일하고, java는 패키지에 존재하는 클래스를 실행하는 역할
exe파일이 아닌 class파일로 컴파일 후 실행
Just In Time 컴파일러의 약자이며, 기존 JVM은 바이트코드로 컴파일 하는 과정과 그 바이트코드를 인터프리터하는 2가지의 과정을 모두 거쳐야 하고 특히나 인터프리터 방식은 런타임 시 코드를 한줄씩 읽어들여 실행 속도가 느림
-> JIT 컴파일러의 도입
(1) 컴파일 방식 : 소스코드를 한꺼번에 컴퓨터가 읽을 수 있는 native machine (기계)어로 변환
(2) 인터프리터 방식 : 소스코드를 빌드시에 아무것도 하지 않다가, 런타임시에 한줄 한줄 읽어가며 변환
WORA(Write once, run anywhere)을 구현하기 위함이라고 할 수 있다.
자바 컴파일러를 사용하는 이유: 자바는 물리적인 머신과 별개의 가상 머신(JVM)을 기반으로 동작하도록 설계되었기 때문이다. 자바 바이트코드를 실행하고자 하는 모든 하드웨어에 JVM을 동작시킴으로써 자바 실행 코드를 변경하지 않고도 모든 종류의 하드웨어에서 동작되게 한 것이다. Java 소스코드(.java)는 CPU가 인식을 하지 못하므로 기계어로 컴파일을 해줘야 한다. 하지만 Java는 JVM이라는 가상 머신을 거쳐서 OS에 도달하기 때문에 OS가 인식할 수 있는 기계어로 바로 컴파일되는 게 아니라 JVM이 인식할 수 있는 자바 바이트코드(.class)로 변환된다. 자바 컴파일러가 .java 파일을 .class 파일인 자바 바이트코드로 변환한다.
자바 인터프리터를 사용하는 이유: JVM이 인터프리터를 사용하는 이유는 컴파일러의 경우 기계, 물리적인 머신에 종속되므로 자바는 자바 컴파일러로 생성된 바이트코드를 인터프리터가 기계어로 번역해서 실행한다. 초기 실행속도와 보안 측면에서 장점이 있다(한줄씩 읽음).
JVM은 가장 자주 실행되는 코드 블록, 메서드 또는 메서드의 일부, 특히 반복문을 모니터링해서 네이티브 코드로 컴파일-> 불필요한 번역과정을 생략하여 실행속도 향상
JIT 컴파일러는 실행 시점에서는 인터프리터와 같이 기계어 코드를 생성하면서 해당 코드가 반복적인 코드라면 컴파일하고 그 코드를 캐싱(저장)한다. JIT 컴파일은 코드가 실행되는 과정에 실시간으로 일어나며(Just-In-Time), 전체 코드의 필요한 부분만 변환한다. 이미 한 번 읽어서 기계어로 변환된 코드는 캐시에 저장되기 때문에 다시 컴파일하지 않는다.
JIT 컴파일러가 컴파일하는 조건은 얼마나 자주 코드가 실행됐는가 이다. 메서드가 호출된 횟수, 메서드의 루프를 빠져나오기까지 돈 횟수 두 개를 기반으로 한다.
JIT 컴파일 과정은 별도의 스레드에서 실행되고, JVM 스레드는 JIT 컴파일 스레드의 영향을 받지 않기 때문에 애플리케이션의 실행에 영향을 주지x
컴파일이 진행중일 때에는 인터프리터 방식으로 동작하지만, 컴파일이 완료되면 컴파일 된 버전을 사용
=> on-stack replacement(OSR)
쉽게 말해서 컴파일러가 최적화를 미리 해주고(컴파일 과정은 시간이 소요됨) 인터프리터에서 반복되는 코드를 읽지 않고 컴파일 된 코드를 바로 사용함으로써 기계어 번역 시간을 단축한다.
JIT 컴파일러는 C1 (클라이언트 컴파일러), C2(서버 컴파일러)로 구분되는데 C1은 빠르게 실행되지만 덜 최적화 된 코드를 생성하며, C2는 실행 시간이 좀 더 걸리지만 더 최적화된 코드를 생성힌다. 오늘날의 JVM은 두 가지를 모두 사용한다.
C2는 C++과 견줄 수 있는 속도의 코드를 생성하며, 몇가지 문제가 있어서 새로운 프로젝트가 진행되었는데, 이를 GraalVM이라고 한다.