JVM 메모리 구조

리리티·2022년 11월 7일
0

JVM 메모리 구조

클래스 로더가 컴파일된 자바 바이트코드를 런타임 데이터 영역에 로드하고 실행 엔진이 자바 바이트 코르를 실행한다.

Class Loader

자바는 컴파일타임이 아니라 런타임에 클래스를 처음으로 참조할 때 해당 클래스를 로드하고 링크하는 특징이 있다. 이 동적 로드를 담당하는 부분이 JVM의 클래스 로더이다.


클래스 로더 특성

1) 계층 구조

  • 클래스 로더끼리 부모-자식 관계를 이루어 계층 구조로 생성
    • 최상위 클래스 로더는 부트스트랩 클래스 로더

2) 위임 모델

  • 계층 구졸르 바탕으로 클래스 로더끼리 로드를 위임하는 구조로 동작
    • 클래스를 로드할 때 먼저 상위 클래스 로더를 확인하여 상위 클래스 로더에 있다면 해당 클래스를 사용
      • 상위 클래스 로더가 없다면 로드를 요청받은 클래스 로더가 클래스를 로드한다.

3) 가시성 제한

  • 하위 클래스 로더는 상위 클래스 로더의 클래스를 찾을 수 있다. 하지만 상위 클래스 로더는 하위 클래스 로더의 클래스를 찾을 수 없다.

4) 언로드 불가

  • 클래스 로더는 클래스를 로드할 수 있지만 언로드 불가.
    • 하지만 언로드 대신 현재 클래스 로더를 삭제하고 아에 새로운 클래스 로더를 생성하는 방법을 사용
  1. 각 클래스 로더는 로드된 클래스들을 보관하는 네임스페이스를 갖는다.
  2. 클래스를 로드할 때 이미 로드된 클래스인지확인하기 위해서 네임스페이스에 보관된 FQCN을 기준으로 클래스를 찾는다.
  3. FQCN이 갖더라도 네임스페이스가 다르면 다른 클래스 로더가 로드한 클래스이면 다른 클래스로 간주한다.
  • FQCN(fully qualified class name)

클래스 로더 위임 모델

클래스 로더가 클래스 로드를 요청 받으면 클래스 로더 캐시, 상위 클래스 로더, 자기 자신의 순서로
해당 클래스가 있는지 확인

거슬러 올라가며 확인하는데 부트스트랩 클래스 로더까지 확인ㅎ도 없으면 요청 받은 콜래스
로더가 파일 시스템에서 해당 클래슬르 찾는다.

부트스트랩 클래스 로더

  • JVM을 기동할 때 생성, Object 클래스들을 비롯하여 자바 API들을 로드
  • 네이티브 코드로 구현되어 있다.

익스텐션 클래스 로더

  • 기본 자바 API를 제외한 확장 클래스들을 로드
  • 다양한 보안 확장 기능 등을 여기서 로드

시스템 클래스 로더

  • 시스템 클래스 로더는 애플리케이션의 클래스들을 로드
    • 사용자가 지정한 $CLASSPATH 내의 클래스들을 로드

사용자 정의 클래스 로더

  • 애플리케이션 사용자가 직접 코드 상에서 사용해서 사용하는 클래스 로더

부트스트랩 클래스 로더와 익스텐션 클래스 로더는 JVM자체의 구성 요소들을 로드한 것이라 할 수 있다.

웹 애플리케이션 서버와 같은 컨테이너는 웹 애플리케이션과 엔터프라이즈 애플레키이션이 서로 독립적으로 작동하도록 사용자 정의 클래스 로더를 사용

  • 클래스 로더의 위임 모델을 통해 애플리케이션의 독립성을 보장

클래스 로드 과정

  • 로딩 : 클래스 파일에서 가져와 JVM의 메모리에 로드

  • 검증(Verifying) : 읽어 들인 클래스가 자바언어 명세 및 JVM 명세에 명시된 대로 잘 구성됐는지 검사

    • 가장 까다롭게 검사하며 가장 복잡하고 시간이 많이 걸린다.
  • 준비(Preparing) : 클래스가 필요로 하는 메모리를 할당, 클래스에서 정의된 필드, 메서드, 인터페이스를 나타내는 데이터 구조를 준비

  • 분석(Resolving) : 상수 풀 내 모든 심벌릭 레퍼런스를 다이렉트 레퍼렌스로 변경

  • 초기화(Initializer) : 클래스 변수를 적절한 값으로 초기화

    • static initializer 실행하고, static 필드를 설정된 값으로 초기화

symbolic reference : 참고하는 클래스의 특정 메모리 주소를 참조 관계로 구성한 것이 아니라 참조하는 대상의 이름만을 지칭한 것

direct reference : 참조하는 클래스의 특정 메모리 주소를 참조하는 것

JVM 명세는 이 작업에 대해 명시하고 있으나 작업에 따라서 실행 시점은 유연하게 적용 가능


런타임 데이터 영역

JVM이라는 프로그램이 운영체제 위에서 실행되면서 할당받는 메모리 영역

1) Method Area

  • 모든스레드에 정보가 공유하며 JVM 시작할때 생성
  • 클래스, 인터페이스에 대한 런타임 상수 풀,필드와 메서드 정보, static 변수, 메서드의 바이트코드 등을 보관
  • 메서드 영역은 JVM 제조사마다 다양한 형태로 구현할 수있다.
    • EX) 오라클 핫스폿VM에서는 Permanent area

2) Heap

  • new로 생성된 객체, Array와 같은 동적으로 생성된 데이터가 저장되는 공간
  • GC가 동작하여 메모리 관리
  • Reference Type의 데이터가 저장되는 공간

3) JVM Stack

  • 스택 프레임이라는 구조체를 저장하는 스택
  • JVM은 오직 JVM스택에 스택 프레임을 추가하고 꺼내는 작업만 실행
  • 예외 발생 시 printStackTrace() 등의 메서드로 보여 주는 스택 트레이스의 각 라인은 하나의 스택 프레임을 표현한다.
  • 스레드마다 하나씩 존재하며 스레드가 시작할 때 생성한다.

4) PC Register

  • 쓰레드가 시작될때 생성
  • 생성될 때마다 생성되는 공간으로 쓰레드마다 하나씩 존재
  • 쓰레드가 어떤 부분을 무슨 명령으로 실행해야하는지 기록을 하는 부분
  • 현재 수행중인 JVM 명령의 주소를 갖는다.

5) Native Method Stack

  • 자바 외 언어로 작성된 네이티브 코드를 위한 메모리 영역

6) Runtime Constant Pool

  • 클래스 파일 포맷에서 constant_pool 테이블에 해당하는 영역
  • 메서드 영역에도 포함되긴 하지만 JVM 작동에 가장 핵심적인 역할을 실행하는 곳
    • JVM명세에도 따로 기술해둠
  • 각 클래스와 인터페이스의 상수뿐 아니라 메서드와 필드에 대한 모든 레퍼런스까지 담고 있는 테이블
  • 어떤 메서드나 필드를 참조할 때 JVM은 런타임 상수 풀을 통해 해당 메섣나 필드의 실제 메모리상의 주소를 찾아서 참조

JVM 스택 구성

1) 스택 프레임

  • JVM 내에서 메서드가 실행될 때마다 하나의 스택 프레임이 생성돼 해달 스레드의 JVM 스택에 추가되고 메서드가
    종료되면 스택 프레임이 제거
  • 각각의 스택 프레임은 지역 변수 배열, 피연산자 스택, 현재 실행 중인 메서드가 속한 클래스의 런타임 상수 풀에 대한 레퍼런서를 갖는다.
  • 지역 변수 배열, 피연산자 스택의 크기는 컴파일 시에 결정되기 때문에 스택 프레임의 크기도 메서드에 따라 크기가 고정

2) 지역 변수 배열

  • 0부터 시작하는 인덱스를 가진 배열
  • 0은 메서드가 속한 클래스 인스턴스의 this 레퍼런스
  • 1부터 메서드에 전달된 파라미터가 저장
  • 메서드 파라미터 이후에는 메서드의 지역 변수가 저장

3) 피연산자 스택

  • 메서드의 실제 작업 공간
  • 각 메서드는 피연산자 스택과 지역 변수 배열 사이에서 데이터를 교환하고 다른 메서드의 호출 결과를 추가하거나 꺼낸다.
  • 피연산자 스택 공간이 얼마나 필요한지 컴파일 할때 결정할 수있으므로 피연산자 스택의 크기는 컴파일시에 결정된다.

실행 엔진(Execution Engine)

클래스 로더를 통해 JVM 내의 런타임 데이터 영역에 배치된 바이트코드는 실행 엔진에 의해 실행

바이트 코드의 각 명령어는 1바이트짜리 OpCode와 추가 피연산자로 이루어져 있으며 실행 엔진은 하나의 OpCode를 가져와서 피연산자와 작업을 수행한 다음, 그 다음 OpCode를 수행하며 작동한다.

참조

네이버를 만든 기술, 읽으면서 배운다 - 자바편

profile
remind

0개의 댓글