콘텐츠로 이동

2021 05 24

2021-05-24

JVM 이해하기

  • 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

클래스 로더

  • 참고: https://www.geeksforgeeks.org/jvm-works-jvm-architecture/
  • 로딩 -> 링크 -> 초기화 순으로 진행
  • 로딩 - 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: 기존의 심볼릭(논리적인) 메모리 레퍼런스를 실제 메서드 영역에 있는 실제 레퍼런스로 변경
  • 초기화 - Static 변수 할당, Static 블록 실행