• 바이트코드는 JVM이 읽는 언어.

.class 파일과 바이트 코드 소개

  • .java compile .class
  • 자주 쓰이는 바이트 코드 native머신 언어로 변형. 바이트코드 네이티브 코드 JIT

클래스 로더

  • 이름을 알고 있는 특정 클래스에 대한 정의(Byte Stream)을 가져오는 역할 수행
  • 부트스트랩 클래스 로더
    • JVM에서 라이브러리로 취급(rt.jar, tools.jar)되는 것들을 로드 (핫스팟에서는 C++로 구현)
  • 플랫폼 클래스 로더(기존 확장 클래스 로더)
    • 클래스 라이브러리 로드
  • 애플리케이션 클래스 로더
    • sum.misc.Launcher$AppClassLoader 의미

클래스 로더 별 담당 모듈(일부)

  • Bootstrap
    • java.base
    • java.desktop
    • java.logging
    • java.naming
    • java.net
    • java.sctp
  • Platform
    • java.compiler*
    • java.cobar*
    • java.sql
    • java.charset
    • java.jsobjdct
    • java.security.auth
    • java.xml.dom
  • Application
    • jdk.complier
    • jdk.hotspot.agent
    • jdk.jartool
    • jdk.jcmd
    • jdk.jshell
    • jdk.pack

compile link runtime

Java 클래스 로딩

  • 클래스 로딩 및 링킹 과정이 모두 런타임에 이루어짐
  • 실행 성능이 일부 저하될 수 있으나 높은 확장성과 유연성을 제공하는 근간
    • 인터페이스만 맞으면 Runtime에 구현 클래스를 결정하지 않을 수 있음
    • 클래스 로더는 실행할 프로그램 코드를 네트워크로 수신하는 것도 가능
  • 해석(Resolution) 단계는 동적 바인딩(혹은 늦은 바인딩)을 지원할 목적으로 초기화 후로 지연될 수 있음

클래스 검증

  • JVM 명세가 정하는 규칙, 제약을 만족하는지 확인
    • 파일 형식(.class)
    • 메타데이터
    • 바이트코드
    • 심벌 참조
  • 보안위협에 대한 검증 포함
    • 바이트코드 검증 시 함께 확인

준비 및 해석

  • java.lang.Class 인스턴스(메타 데이터)가 힙 영역에 생성되고 클래스 변수(정적 멤버) 메모리를 0으로 초기화
    • 로드되는 클래스의 인스턴스는 Using 단계에서 힙 사용
    • final 선언된 변수는 코드에서 정의한 초깃값으로 정의(0이 아닐 수 있음)
  • 생성자 호출 전 상태(new 연산 전)
    • 필드(인스턴스 변수) 초깃값은 생성자 호출 시 정의
    • 정적 필드에 초깃값 할당
  • 해석은 상수 풀의 심벌 참조를 직접 참조로 대체하는 과정

Heap 영역에 객체 생성

  • JVM은 객체 저장을 위한 메모리 공간 확보 후 0으로 초기화(단, 객체 헤더 제외)
  • 객체 초기화 위한 구성 설정 실시
    • 클래스 이름 및 메타 정보 확인 방법
    • 객체에 대한 해시코드
    • GC 세대 나이
  • 생성자 호출

JVM runtime data area

Method area(Runtime constant pool)

  • JVM이 읽어 들인 각종 타입 정보, 상수, 정적(static) 변수 정보가 저장되는 영역
  • JIT(Just In Time) 컴파일러가 번역한 기계어 코드를 개싱하기 위한 메모리 공간으로 활용
  • Java 8 부터는 PermGen이 아니라 Metatspace에 속함.
    • Metaspace는 JVM 힙이 아니라 네이티브 메모리에서 관리하며, 크기가 동적으로 달라질 수 있음

Runtime constant pool

  • 클래스 버전, 필드, 메서드, 인터페이스 등 클래스 파일에 포함된 정보 및 각종 리터럴, 심볼 참조가 저장되는 영역
  • 클래스 로더가 클래스 로드할 때 상기 정보들을 저장
  • 동적으로 운영되며 런타임에 새로운 상수 추가될 수 있음

Stack area

  • 지역 변수 테이블, 피연산자 스택, 메서드 반환값 등 저장
    • C/C++의 스택보다 더 복잡한 구조
  • 보통 지역변수 테이블을 스택으로 지칭
  • 지역변수 테이블은 슬롯으로 이뤄지며 기본형 변수 하나가 슬론 한개(혹은 2개) 사용
  • Java 스택의 크기는 메모리 용량이 아닌 슬롯의 개수
  • JVM이 허용하는 스택의 크기 초과 시, StackOverflowError 발생

Native method stack

  • C++로 개발된 Native 코드(함수 단위)가 실행 될 때 지역변수 및 자동변수가 사용하는 스택 메모리
  • 구현하기에 따라 JVM stack과 합쳐서 사용하기도함

JVM Heap 영역

  • GC가 관리하는 메모리 영역
  • Java에서 사용되는 객체의 인스턴스 및 배열이 저장되는 공간
  • 설정에 따라 크기를 변경하거나 고정할 수 있음
    • 부족시 OutOfMemoryError 발생
  • 세대별 컬렉션 이론(Generational Collection Theory)을 기반으로 설계 및 운영
    • Eden, Survivor
    • New/Old generation
    • 영구 세대(Metaspace)

JVM GC

  • Heap 에서 참조되지 않는 개체를 수집 및 제거해 메모리 회수
  • Minor/Major(Full) GC
    • GC 수행 시 프로그램 일시 정지
    • stop the world
  • GC 속도
    • Minor GC가 보통 1초 이내 완료
    • Full GC는 수 초 이상 진행되기도 하며 이 지연 때문에 DB연결이 끊기는 등 운영문제 발생할 수 있음

GC 기술의 시작

  • Java에서 거의 모든 인스턴스는 힙에 저장
  • GC는 1960년대 만들어진 리스프
  • GC가 처리해야할 문제의 핵심 3요소(by 리스프 창시자 존 맥카시)
    • 회수 대상 메모리 판단
    • 메모리 회수 시점
    • (구체적인) 메모리 회수 방법