본문 바로가기
Java/basic

JVM 아키텍쳐 구성요소

by Ellery 2022. 4. 7.

JVM에 대한 정의는 해당 포스트를 참고해주세요.

https://medium.com/platform-engineer/understanding-jvm-architecture-22c0ddf09722

JVM이 동작하는 순서는 다음과 같다. (구성요소 - class loader, runtime data area, execute engine, JNI...)

  1. 자바 프로그램을 실행하면 JVM은 OS로부터 메모리를 할당한다.
  2. 자바 컴파일러(javac)가 자바 소스코드(.java)를 자바 바이트코드(.class)로 컴파일한다.
  3. Class Loader를 통해 JVM Runtime Data Area로 로딩한다.
  4. Runtime Data Area에 로딩 된 .class들은 Execution Engine의 인터프리터와 JIT 컴파일러를 통해 해석합니다.
  5. 해석된 바이트 코드는 Runtime Data Area의 각 영역에 배치되어 수행하며 이 과정에서 Execution Engine에 의해 GC가 작동하고, 스레드 동기화가 이루어진다.
  1. Class loader 시스템: 바이트를 실행할 때 class 객체를 메모리에 생성하는 요소.
    클래스의 인스턴스를 생성하면 클래스로더를 통해서 메모리에 로드한다.
    기본적으로 클래스로더 기능은 3가지가 제공된다. - 로딩, 링크, 초기화 기능.
    1. 로딩: .class파일에서 읽고 그 내용에 따라 바이너리 데이터를 이를 메소드영역에 저장한다.
      로딩이 끝나면 해당 클래스 타입의 class객체를 생성해서 힙 영역에 저장한다. 
      해당 클래스 정보를 FQCN이라고 한다. (fully qualified class name.) 클래스, 인터페이스, enum, 메서드, 변수를 저장함
      • 부트스트랩 클래스로더: JAVA_HOME\lib 에 있는 코어 자바 API를 제공한다. 최상위 우선순위를 가짐
      • 플랫폼 클래스로더: JAVA_HOME\lib\ext 폴더 혹은 java.ext.dirs 시스템 변수에 해당하는 위치에 있는 클래스를 읽는다.
      • 어플리케이션 클래스로더: 어플리케이션 클래스패스(어플리케이션 실행할 때 주는 -classpath 옵션 혹은 java.class.path 환경 변수의 값에 해당되는 위치)에서 클래스를 읽는다.
      • 어떤 클래스를 읽어올 때 최상위 부모(부트스트랩)부터 읽기 시작해서 모든 클래스로더가 읽지 못하면 ClassNotFoundException이 발생한다. 대부분 application 클래스로더가 읽게 된다. (스프링 등..)
    2. 링크: 레퍼런스를 연결
      • verify: .class파일 형식이 유효한지 체크
      • prepare: 클래스변수(static)와 기본값에 필요한 메모리를 준비하는 과정.
      • resolve: 심볼릭 메모리 레퍼런스()를 메소드 영역에 있는 실제 레퍼런스와 교체한다. (optional: )
    3. 초기화: static 값들을 초기화하고 변수에 할당함
  2. Runtime data area(메모리): OS에서 JVM이 실행될 때 할당되어 있는 메모리영역이고, 모든 쓰레드의 공유공간이다.
    • method area(class area): 클래스 수준의 정보를 저장함(Type info, Runtime Constant pool, Field info, method info, class variables)
      • type info: 해당 클래스, 하위 클래스들 이름, 해당 클래스의 클래스-인터페이스 여부, 클래스의 modifier(접근제어자, abstract 등), 연관된 인터페이스 리스트
      • runtime constant pool: 해당 클래스에 들어있는 모든 상수정보(type, field, method의 모든 Symbolic ref), constant pool의 entry는 인덱스로 접근
      • Field info: 들어있는 필드값들에 대한 정보(type, modifier - 접근 제어자나 static, final, volatile, transient 같은 그 외 제어자들)
      • method info: 메서드 이름, 리턴타입, 파라미터 수와 타입, modifier(접근제어자나 static, final, syncronized, native, abstract), 구현로직, 바이트코드, 메서드의 stack frame operand stack, local variable section 크기, exception table
      • class variable: static 변수(클래스변수는 클래스에 속하게 됨. 클래스를 사용하기 이전에 이미 메모리를 할당받음)
        • static 변수는 메서드 영역에 저장됨. 기본형이 아닌 static 클래스변수는 변수의 주소를 저장하고, 실제 인스턴스는 힙메모리에 저장된다.
        • final static으로 선언된 클래스 상수변수는 runtime constant pool에 값을 복사한다.
    • heap area: 객체들의 인스턴스가 생성되는 공간. 동적으로 인스턴스가 생성되면 Heap 메모리에 할당되어 사용된다. (Object 타입의 데이터 String, List...)
      • 레퍼런스타입 변수, 배열 등은 heap에 인스턴스가 저장되는 게 아니라 포인터가 저장된다.
      • GC의 대상이 되는 영역이다.
      • 7버전 이후부터는 내부에 String constant pool을 포함하고 리터럴로 초기화된 String 객체들을 효율적으로 관리함
    • 특정 스레드에 국한된 공간
      • PC register: 쓰레드마다 쓰레드 내의 현재 실행할 instruction의 위치를 가리키는 포인터가 생성된다.
      • stack area(JVM Stack): 쓰레드마다 런타임 스택을 만들고, 그 안에 메소드 호출을 스택프레임(메소드 콜)에 쌓는다. 이후 쓰레드가 종료되면 런타임 스택은 사라진다.
      • native method stack: 네이티브 메소드 사용 시 따로 쓰는 스택.
  3. Execution engine(실행 엔진) - 인터프리터, JIT 컴파일러, GC
    • 인터프리터, JIT 컴파일러
      • 바이트코드를 인터프리터를 통해서 한 줄씩 컴파일 - 실행하면서 네이티브 코드로 바꿔서 실행한다.
      • 이 중 반복적인 코드가 발생하는 부분은 JIT컴파일러가 미리 캐싱해놨던 네이티브 코드(기계어)로 변환시켜서 속도를 향상시킨다.
    • GC - 메모리의 stack 영역 데이터, method 영역의 static 데이터, JNI에 의해 생성된 객체에 대하여 동작함
       
      • 객체가 참조되는 동안 JVM은 힙 메모리의 객체가 살아있는 것으로 간주하지만, 이후에 더 이상 참조하지 않으면 GC가 객체를 제거하고 메모리 해제를 한다. GC는 JVM 내부적으로 알아서 실행되지만, System.gc() 메서드로 트리거할 수도 있다. 실행이 보장되지 않을 수 있다. 정말 필요한 경우에는Thread.sleep(1000)을 호출하고 GC가 완료될 때까지 기다린다.
      • 기본적으로 Mark&Sweep 알고리즘으로 동작함. 어떤 객체에 유효한 참조가 있는지 체크 후(Reachability) unreachable한 객체들을 메모리 해제한다
      • 추가로 메모리 단편화를 막기 위해 compact과정을 거치기도 함
      • 경우에 따라 옵션을 조정하여 커스터마이징한다. 어플리케이션 프로파일링 시에도 우리가 어떤 GC를 사용하는지, 경우에 따라 어떤 GC를 사용해야될지 선택해야한다.
      • throughput의 최대화를 위한 GC(처리용량), stop-the-world를 줄이는 GC(반응시간)
      • Serial GC(JDK 5,6), Parallel GC(JDK 8 default), CMS(Concurrent Mark Sweep) collector, G1 GC(자바 7부터 도입, 9부터 default)

https://www.geeksforgeeks.org/mark-and-sweep-garbage-collection-algorithm/

  1. Native
    • JNI: 자바 어플리케이션에서 c, c++, 어셈블리 등으로 작성된 함수를 사용할 수 있는 방법을 제공함. native 키워드를 사용해서 메소드를 호출한다.
    • 네이티브 메소드 라이브러리: c,c++로 작성된 라이브러리

- 백기선님의 자바 온라인 스터디 https://github.com/whiteship/live-study 주제를 정리한 내용입니다.

참고내용: