JVM
-
JVM은 바이트 코드를 실행하는 가상 머신
-
코드 작성(Main.kt) → (컴파일) → 바이트 코드(Main.class) → (런타임) → 기계어 → JVM에서 실행
-
JVM에서 바이트 코드들을 기계어로 변환하는 단계를 거치는게 이 작업을 하는 컴파일러가 JIT 컴파일러
-
기본적으로 메모리를 stack, heap으로 관리함
-
stack: 주소값 (c 언어의 포인터?), static 정보들?
-
heap: 실제 데이터
-
컴파일러
-
컴파일러에서 프로그램 코드를 기계어로 변환할 수 있는 시점은 두 개.
-
프로그램 실행 전 → 정적 컴파일러
-
프로그램 실행 중 → 동적 컴파일러(인터프리트 언어)
-
인터프리터
-
-
-
C, C++과 같이 실행 전에 모두 컴파일하면 컴파일 시간이 길지만 런타임에 성능이 뛰어남
-
js, py 같이 실행중에 컴파일하면 컴파일 시간이 필요없지만 런타임 중 리소스 일부를 컴파일에 사용하기 때문에 프로그램 성능이 떨어질 수 있음
-
이 둘의 단점을 최소화하고 장점을 극대화하는 방향으로 설계된 컴파일러가 JIT 컴파일러
JIT
-
Just-in-Time Compilers
-
소스 코드를 바이트 코드를 만들 때는 정적 컴파일러를 사용
-
바이트 코드를 기계어로 변환할 땐 동적 컴파일러가 아닌 JIT 컴파일러를 사용
-
런타임에 기계어로 변환된 코드를 캐시에 저장하여 재사용시 컴파일하기 않고 그대로 사용
-
캐시된 코드를 사용하면 마지 정적 컴파일과 같은 효과
-
-
하지만, JVM의 캐시 공간은 매우 작으므로 모두 캐싱하지 않음
-
자주 수행되는 코드를 선별함
-
-
JIT 컴파일러 내부에 C1, C2 2가지 컴파일러가 있음
-
C1 컴파일러: 런타임에 바이트 코드를 기계어로 변환하는 과정만 수행
-
C2 컴파일러: 런타임에 파이트 코드를 기계어로 변환한 다음 캐시에 저장하는 과정 수행
-
수행 빈도와 복잡도에 따라 4가지 레벨로 분류하여 코드를 수행
-
이 때 1~3 레벨 코드는 C1 컴파일러를 사용하고 캐싱 안함
-
4레벨 코드는 C2 컴파일러를 사용하여 캐싱함
-
-
-
실제 수행을 보기 위해서 java 파일 실행시
-XX:+PrintCompilation
옵션 추가-
3열이 코드 레벨
-
-
어플리케이션이 커져서 코드를 캐시할 수 있는 메모리 공간이 없다면 C2 컴파일러는 더이상 효율적으로 동작하지 않음
-
이 때 코드 캐시 사이즈를 확인하고 튜닝이 필요함
-
java 실행 시
-XX:+PrintCodeCache
옵션 추가
-
-
Code Cache
컴파일된 메서드의 네이티브 코드 생성을 저장하는데 사용되는 영역.
코드 캐쉬는 거의 성능문제를 발생시키지 않지만, 한번 코드 캐쉬 문제가 생기면 그 효과는 어마어마할 것이다. 만약 코드 캐쉬 메모리를 모두 사용하게 되면, JVM 은 경고 메시지를 출력하고 “interpreted-only mode” 로 전환한다. JIT 컴파일러는 정지되고 더이상 바이트코드(bytecode)는 네이티브 코드로 컴파일 될지 않을 것이다. 따라서 애클리케이션이 동작은 계속되지만 크기의 순서에따라 점점 느려진다.
Option | Description |
---|---|
|
초기 코드 캐시 사이즈. |
|
예약된 코드 캐시 사이즈(최댓값) |
|
코드 캐시 확장되는 단위 크기 |
|
컴파일러 스레드 개수. |
|
서버 컴파일러의 기본값은 10,000 |
Java 8
-
java 8 기존 default code cache: 24mb, max 240mb
Java 11
-
java 11 기준 code heap 사이즈를 합쳐보면 240mb 정도, max 2gb
-
ReservedCodeCacheSize
-
default size: 240MB
-
tiered compilation 옵션을 disable하면 default size: 48MB (
-XX:-TieredCompilation
)
-
-
limit: 2GB
-
최대 값은 초기 코드캐시 값보다 작아서는 안됨 (
-XX:InitialCodeCacheSize
)
-
-
SegmentedCodeCache
-
코드 캐시를 특정 타입의 컴파일된 코드를 포함하는 별도의 세그먼트로 나누는 옵션.
-
non-method, profiled, non-profiled 코드 분리
-
9부터 들어간 옵션(https://openjdk.org/jeps/197)
-
Java 17
Option | Default | Description |
---|---|---|
|
플랫폼에 따라 다름 |
초기 코드 캐시 사이즈 |
|
240 MB |
예약된 코드 캐시 사이즈(최댓값) |
-
ReservedCodeCacheSize
-
default size: 240MB
-
tiered compilation 옵션을 disable하면 default size: 48MB (
-XX:-TieredCompilation
)
-
-
limit: 2GB
-
최대 값은 초기 코드캐시 값보다 작아서는 안됨 (
-XX:InitialCodeCacheSize
)
-
Tiered Compilation
-
java 11 기준으로 CodeHeap(Code Cache)가 3가지 공간으로 나뉨.
-
이것이 Tiered Compiliation 옵션이 생겨서임
-
이를 끄고 싶다면
-XX:-TieredComilation
옵션 추가
-
-
method 종류에 따라 다르게 컴파일하는 옵션