Java & Spring/자바

JVM & GC (JAVA)

Zin0_0 2020. 10. 20. 18:22
반응형

JVM과 GC

  • JVM (Java Virtual Machine)
    • 자바 애플리케이션을 클래스 로더를 통해 읽어서 자바 API와 함께 실행하는 것
    • JAVA와 OS 사이에서 중개자 역할 ~> OS에 구애받지 않고 재사용을 가능하게 함
    • 메모리 관리, Garabage collection을 수행
    • 스택 기반의 가상머신
      • cf) ARM 아키텍처와 같은 하드웨어는 레지스터 기반으로 동작
    • 자바 실행 과정
      • JVM은 OS로부터 프로그램이 필요로 하는 메모리를 할당받음
        • JVM은 이 메모리를 용도에 따라 여러 영역으로 나누어 관리
      • 자바 컴파일러(javac)가 소스코드(.java)를 바이트코드(.class)로 변환
      • Class Loader를 통해 class 파일들을 JVM으로 로딩
      • 로딩된 class 파일들은 Execution engine을 통해서 해석
      • 해석된 bite code는 runtime data area에 배치 ~> 수행
      • 실행과정 속에서 필요에 따라 Thread Synchronization과 GC와 같은 관리작업 수행
    • 구성
      • Class Loader(클래스 로더)
        • 클래스파일을 로드하고 링크를 통해 배치하는 작업을 수행하는 모듈
        • runtime시 동적으로 클래스를 로드
        • jar 파일 내 저장된 클래스를 JVM에 탑재 ~> 사용하지 않는 클래스는 메모리에서 삭제
        • 클래스를 처음으로 참조할 때, 해당 클래스를 로드하고 링크하는 역할
      • Execution Engine(실행 엔진)
        • 클래스를 실행하는 역할로 클래스 로더가 JVM내의 런타임 데이터 영역에 바이트코드를 배치하면, 실행 엔진이 실행
        • 바이트코드는 기계어가 아닌 사람이 보기 편한 형태로 기술 ~> 실행 엔진이 바이트코드를 실제 JVM이 해석할 수 있는 기계어로 변경
      • Interpreter
        • 실행 엔진은 바이트 코드를 명령어 단위로 읽어서 실행
        • 한줄씩 실행하는 인터프리터 언어의 단점을 가지고 있음
      • JIT(Just In Time)
        • 인터프리터 방식의 단점을 보완하기 위해 도입된 JIT 컴파일러
        • 인터프리터 방식으로 실행하다가 적절한 시점에 바이트 코드 전체를 컴파일 ~> 네이티브 코드로 변경 ~> 네이티브 코드로 직접 실행
        • 네이티브 코드는 캐시에 보관 ~> 한 번 컴파일된 코드는 빠르게 수행
        • 컴파일 과정은 인터프리팅보다 오래걸리기 때문에, JVM은 내부적으로 해당 메소드가 얼마나 자주 수행되는지 체크해서 일정 수준을 넘을 때만 컴파일 수행
      • GC(Garbage Collector / Garbage Collection)
        • 아래에 따로 정리
    • Runtime Data Area
      • 프로그램을 수행하기 위해 OS에서 할당받은 메모리 공간
      • runtime data area는 저장 목적에 따라서 5개로 나뉨
      • Method Area( == Class Area == Static Area)
        • 모든 Thread에 공유. 클래스, 변수, Method, static 변수, 상수 정보 등 저장
      • Heap Area
        • 모든 Thread에 공유. new 명령으로 생성된 인스턴스와 객체가 저장
        • 힙 공간은 세개의 영역으로 다시 분할
          • New/Young 영역
            • 객체들이 최초로 생성되는 공간과 이 객체에서 참조되는 객체들이 저장되는 공간
          • Old 영역
            • New area에서 일정 시간 참조하고 살아남은 객체들이 저장되는 공간
            • New area 영역에 객체가 가득차면 GC가 발생
          • Permanent Generation
            • 생성된 객체 정보의 주소값이 저장된 공간
            • Class loader에 의해 로드되는 데이터에 대한 meta 정보가 저장, JVM이 사용
            • Reflection을 동적으로 클래스가 로딩되는 경우에 사용되는데, 내부적으로 Reflection 기능이 자주 사용되는 스프링 프레임워크를 이용할 때, 이 영역에 대한 고려가 필요함
        • 공간이 부족해지면 GC 실행
      • Stack Area
        • 각 스레드마다 하나씩 생성됨
        • Method 내부에서 사용되는 값(지역변수, 매개변수, 리턴값 등)이 저장
      • PC Register
        • 각 스레드마다 하나씩 생성됨
          • 현재 수행중인 JVM 명령 주소값 저장 (CPU의 Register와 비슷한 역할)
      • Native Method Stack
        • 각 스레드마다 하나씩 생성됨
        • OS의 고유 기능(Native)를 Java가 아닌 OS가 구현된 언어(보통 C, C++)로 OS의 고유 기능을 형성
        • 해당 언어의 메소드 호출을 위해 할당되는 구역, 언어에 맞게 stack 형성
        • JNI(Java Native Interface) 표준 규약 제공
  • GC(Garvage Collection / Garvage Collector)
    • GC
    • Young 영역 GC
      • Minor GC
        • 새로 생성된 객체는 Eden 영역에 위치
        • Eden에서 GC가 실행된 이후 살아남은 객체는 Survivor 영역 중 하나로 이동
        • survivor에서 계속 살아있는 객체를 old 영역으로 이동
      • Major GC
        • old 영역에 있는 모든 객체들을 검사 ~> 참조되지 않은 객체를 한꺼번에 삭제
        • 시간이 오래걸리고 실행 중 프로세스가 정지됨, 이를 stop-the-world라고 한다
        • Major GC가 발생 ~> 실행하는 스레드를 제외한 나머지 스레드는 모두 작업을 멈추고, GC 작업을 완료한 이후에 작업 다시 시작
    • Old 영역 GC
      • Serial GC
        • 적은 메모리와 CPU 코어 개수가 적을 때 적합한 방식
        • Old 영역에 살아있는 객체 식별 후, 힙의 앞부분부터 살아있는 것만 남기고, 각 객체들이 연속되게 쌓이도록 힙의 앞부분부터 채워서 객체가 존재하는 부분과 객체가 없는 부분으로 나눈다.
      • Parallel GC
        • Serial GC와 기본적인 알고리즘은 같지만(Mark-Sweep-Compaction), 멀티 쓰레드로 GC를 처리
        • 따라서, Serial GC보다 빠르게 처리 가능
        • 메모리가 충분하고 코어의 개수가 많을 때 적합한 방식
      • Parallel Old GC
        • JDK 5 update 6부터 제공
        • 개선된 알고리즘(Mark-Summary-Compaction) 사용
        • Summary 단계에서 이미 GC가 수행된 영역에서 살아있는 객체를 식별하는 작업을 한다는 것이 Sweep과 차이점
        • Old GC 처리량을 늘려주기 위한 작업
      • Concurrent GC
        • 프로세서가 GC와 처리 역할을 나누어 작업 ~> 일시 정지가 짧아짐
        • 프로세서의 수를 늘릴수록 효과 O, but 한계가 존재
        • 전체 처리량보다 응답 시간이 더 중요한 경우 사용
    • 소멸 대상 선정 방식
      • 알고리즘에 따라 다양하지만, 공통점이 존재
      • 힙 영역 안의 객체 중에서 가비지를 찾고 처리해서 메모리를 회수한다.
      • 참조되고 있지 않은 객체를 가비지라 하고, reachability라는 개념을 활용함
      • 힙 영역에 할당된 객체가 유효한 참조가 있으면 reachability, 없으면 unreachability
      • 참조 사슬 중 최초 참조한 것을 Root Set이라고 칭함
      • 힙 내의 다른 객체에 의한 참조를 제외한 참조가 Root Set이 된다.
        • Java 메서드 실행 시 사용되는 지역변수와 파라미터들에 의한 참조
        • JNI에 의해 생성된 객체에 대한 참조
        • 메서드 영역의 정적 변수에 의한 참조
반응형