JVM
- 참고: https://howtodoinjava.com/java/basics/jdk-jre-jvm/
- 참고: https://blog.jamesdbloom.com/JVMInternals.html
- [Java 프로그램의 실행]
1. Simple.java 파일 작성
2. javac 컴파일러를 통해 Simple.class로 바이트코드 생성
3. 바이트코드(클래스파일)을 실행할 수 있는 JVM에서 실행
4. JVM이 바이트코드를 native machine code로 변환하여 실행
- [JVM이란?]
- JVM은 자바 바이트코드를 실행하는 가상 머신임
- 가장 인기있는 JVM은 오라클의 Hotspot
- GC와 adaptive optimizer를 통해 자바 어플리케이션의 최적 실행을 보장
- JVM은 client / server 버전으로 출시
- server는 최적화된 속도로 수행
- JVM이 virtual이라 불리는 이유는 실행하는 기계의 os/hw에 종속적이지 않기 때문
- [ClassLoader]
- 클래스 파일을 로드하는데 사용
1. Loading
- Bootstrap - Extension - Application 수행
- 클래스 파일 로드할 때, JVM은 임의의 클래스에 의존성을 찾아냄
- Bootstrap은 jre\lib\rt.jar 파일을 스캔
- 못 찾으면, Extension 클래스 로더가 클래스 파일을 jre\lib\ext에서 찾아봄
- 못 찾으면, Application 클래스 로더가 모든 jar 파일과 classpath내의 클래스를 찾아봄
- 이래도 못 찾으면 ClassNotFoundException 발생
2. Linking
- 클래스가 클래스 로더에 로딩되면, 링킹이 수행됨
- Bytecode verifier가 생성된 바이트코드가 올바른지 검증
- static 변수들과 클래스 메서드들의 메모리 배치를 수행
3. Initialization
- Static 변수들이 할당
- Static 블록이 수행!
- [JVM Memory Area]
- Method Area
- 클래스 구조를 메타데이터 처럼 가짐
- Constant Runtime Pool
- 메서드의 코드
- Heap
- 어플리케이션 수행중에 생성되는 객체 저장
- Stacks
- 각 스레드에서 로컬 변수, 중간 연산 결과 저장
- 각 스레드 별로 JVM 스택이 있음
- PC register
- Statement의 물리적 주소를 저장
- 각 스레드 별로 PC register
- Native Code
- C/C++ Low level 코드를 스택에서 실행
- [JVM Execution Engine]
- 모든 코드는 Execution Engine에 할당됨
- 하나씩 수행
- Interpreter, JIT compiler를 통해 바이트코드 -> 머신코드
- Interpreter
- 바로 바이트 코드를 최적화 없이 수행
- JIT Compiler
- 코드 블럭을 가져와 최적화하고 머신코드로 바꿈
- 기본적으로 사용됨
- [JNI]
- Native Method Library를 가져와 C/C++ 수행
JVM Run-time Data Areas
- 참고: https://javapapers.com/core-java/java-jvm-run-time-data-areas/#Program_Counter_PC_Register
-
- [Managed per-Thread]
- PC Register
- 멀티스레딩 지원. 쓰레드별로 인스트럭션 수행토록 함
- native 실행중이면 PC는 "undefined"
- JVM Stacks
- Memory size가 2가지, fixed/varying 이 있음
- StackOverflowError: fixed size JVM stack에 메모리가 꽉 차서 넘치면
- OutOfMemoryError: dynamic size JVM stack에 메모리가 더 이상 할당 불가라면
- Native Method Stacks
- native method를 수행하기 위해 사용
- [Shared with all threads]
- Heap
- VM 시작시 생성
- GC를 통해 메모리 관리
- 메모리가 부족해지면 OutOfMemoryError
- Method Area
- Heap Area의 논리적 부분 (JVM 벤더가 결정)
- method data, method, constructor code, run-time constant pool 관리
- 메모리가 부족해지면 OutOfMemoryError
- Run-time constant pool
- String pool 같은거 관리
- constant pool table을 통해 클래스 별 관리할 수 있는 거 관리
Thread
- Hotspot JVM은 자바 쓰레드와 OS 쓰레드 1:1 매핑 지원
- Main 백그라운드 시스템 쓰레드는...
- VM Thread
- Periodic Task Thread
- GC Thread
- Compiler Thread
- Signal Dispatcher Thread
로딩
- ClassLoader가 .class 파일 읽어, 내용에 따라 적절히 바이너리 데이터를 만들어, "메소드" 영역에 다음을 저장
- Fully Qualified Class Name (패키지 경로 포함 클래스 이름)
- 바로 위 부모 클래스
- 클래스 / 인터페이스 / 이넘
- 접근제어자 / 메서드 / 변수
- ClassLoader는 3가지가 제공되며 계층 구조로 구성됨
- {BootStrap ClassLoader}
- “JAVA_HOME/jre/lib” 에 있는 코어 자바 API
- 최상위 우선순위
- 주로 C, C++로 작성됨
- {Platform ClassLoader}
- “JAVA_HOME/jre/lib/ext” || java.ext.dirs 시스템 변수의 클래스
- {Application ClassLoader}
- classpath, java.class.path 에서 클래스 읽음
- 로딩이 끝나면, 해당 클래스 타입의 Class 객체 하나를 생성해 "힙" 에 저장
- getClass()로 가져오기 가능
링크
- Verify -> Prepare -> Resolve
- Verify: .class 파일 형식 유효성 검증... 파토나면 java.lang.VerifyError
- Preparation: 클래스 변수와 기본값에 필요한 메모리 준비
- Resolve: 기존의 심볼릭(논리적인) 메모리 레퍼런스를 실제 메서드 영역에 있는 실제 레퍼런스로 변경