[JAVA] JVM - Runtime Data Area

impala·2022년 12월 28일
0

JAVA

목록 보기
4/6
post-thumbnail

Runtime Data Area

JVM이 운영체제로부터 할당받은 메모리영역.

Runtime Data Area는 총 다섯개의 영역으로 이루어져 있다.

  • Method Area : 클래스에 대한 정보가 올라오는 영역. 모든 쓰레드가 공유
  • Heap : new 키워드를 통해 생성된 인스턴스가 생성되는 영역. 모든 쓰레드가 공유
  • Stack : 지역변수, 매개변수, 리턴값 등 임시적으로 사용되는 값들이 저장되는 영역
  • PC Register : 현재 쓰레드가 실행되는 부분의 주소와 명령을 저장하는 영역
  • Native Method Stack : Native 언어로 작성된 코드를 실행하기 위한 영역

위의 그림처럼 Runtime Data Area의 Stack, PC Register, Native Method Stack은 쓰레드가 생성될 때마다 하나씩 새로 생성되어 쓰레드에 할당되고, Method Area와 Heap은 JVM이 시작될 때 할당되어 모든 쓰레드가 공유한다.
이 때, 각각의 쓰레드는 다른 쓰레드에게 할당된 메모리 영역을 침범할 수 없기 때문에 코드를 작성할 때 지역변수의 동시성 문제를 고려하지 않아도 된다.


Method Area

클래스에 대한 정보가 올라오는 영역으로 모든 쓰레드가 공유함. Static영역

프로그램 실행 중 클래스나 인터페이스를 사용하게 되면 JVM은 ClassLoader에게 요청하여 클래스와 인터페이스의 메타데이터를 Method Area에 저장한다.

클래스에 대한 정보가 이 영역에 존재하기 때문에 인스턴스를 생성하기 위해서는 Method Area를 참조해야 하며, 따라서 모든 쓰레드가 이 영역을 공유하게 된다.

Method Area에 저장되는 Metadata는 다음과 같다.

  1. Type Information : 클래스와 인터페이스의 정보
    • Type의 이름(Symbolic reference) : 패키지 이름을 포함한 클래스의 이름
    • Type의 종류 : Class OR Interface
    • Type의 제어자 : 접근제어자(public, private 등) 및 기타 제어자(abstract, final 등)
    • 연관된 Interface의 정보 : Class에 사용된 Interface의 정보
  1. Runtime Constant Pool : Type의 상수 정보를 저장하는 Pool. 인덱스를 통해 접근이 가능
    • 클래스와 인터페이스 상수, 메소드와 필드에 대한 모든 Reference를 저장
    • JVM에서는 해당 메소드와 필드의 실제 메모리상의 주소를 찾기 위해 참조함
    • Method Area에 클래스의 정보가 올라오면 Constant Pool에 대한 포인터를 하나 생성한여 언제든지 클래스 내의 상수에 대해 접근이 가능하도록 한다.
  1. Field Information : 인스턴스 변수의 정보를 저장한다
    • Type명 : 인스턴스 변수의 타입
    • Type의 제어자 : 접근제어자(public, private 등) 및 기타 제어자(abstract, final 등)
  1. Method Infeomation : 메소드의 모든 정보를 저장한다
    • Method 이름
    • Method return type
    • Method parameter수와 각 parameter의 type정보
    • 필요한 메소드에 대한 정보들
  1. Clas Variable : static 키워드로 선언된 변수를 저장한다

즉, Method Area에는 Class에 대한 모든 정보가 Byte Code의 형태로 로드된다.


Heap

new 키워드를 통해 동적으로 생성된 인스턴스 객체가 저장되는 영역으로 모든 쓰레드가 공유하며, Garbage Collection의 대상이 되는 영역이다

Heap에는 프로그램이 실행되면서 동적으로 생성된 인스턴스가 저장되고, 그 Reference를 Stack에 저장한다. 즉, Heap영역에 있는 인스턴스는 접근하기 위해서는 Stack에 저장되어있는 Reference를 통해 접근이 가능하다.

만약 Heap영역이 가득 차게 되면 OutOfMemoryError가 발생한다

또한 JVM은 효율적인 메모리영역의 관리를 위해 Garbage Collection을 수행하는데, Heap 영역이 Garbage Collection의 대상이 된다.

Heap영역은 효율적인 Garbage Collection을 위해 크게 3가지 영역으로 구분된다.

  1. Young(New) Generation
    • new 키워드를 통해 새로운 인스턴스가 생성되면 Eden영역에 저장되고, 이후 Servivor로 이동하게 된다.
    • 시간이 지나면서 이 영역에 있는 데이터는 우선순위에 따라 Old영역으로 이동하거나 GC에 의해 회수된다(Minor GC)
  1. Tenured(Old) Generation
    • Young Generation영역에 저장되었던 객체 중 오래된 인스턴스가 이동되어 저장되는 영역.
    • Old영역에 할당된 메모리가 허용치를 넘게 되면, Old영역에 있는 모든 인스턴스들을 검사하여 참조되지 않는 인스턴스를 한꺼번에 삭제한다(Major GC)
    • Major GC가 발생하면 GC를 실행하는 쓰레드를 제외한 모든 쓰레드가 작업을 중지한다(Stop-the-World)
  1. Permanent Generation(Metaspace)
    • ClassLoader에 의해 동적으로 로딩된 클래스의 메타데이터가 저장되는 영역
    • Java 8 이후 Metaspace로 대체되어 Heap영역에서 제외되었다

Stack

지역변수, 메소드의 매개변수, 리턴값 등 임시적으로 사용되는 값들이 저장되는 영역으로 PC Register, Native Method Stack과 함께 쓰레드가 생성될 때마다 할당된다.

프로그램 실행 시 메소드가 실행되면 JVM은 Stack영역에 해당 메소드의 frame을 push하고, 데이터를 임시적으로 저장한다. 메소드가 종료되면 Stack에서 해당 메소드의 frame을 pop한다.

Stack의 기본 자료구조인 Frame은 아래 세 가지 요소로 구성되어있다.

  • Constant Pool Reference : Method Area의 Runtime Constant Pool에 대한 참조

    • 메소드가 속한 클래스의 상수를 사용하기 위해 Runtime Constant Pool에 대한 참조값을 가진다
  • Local Variables Array : 매소드 내의 지역변수를 담고있는 배열

    • 첫번째 인덱스에는 현재 인스턴스에 대한 참조값을 저장(this)
    • 두번째 인덱스부터 매개변수 -> 지역변수 순으로 값을 저장
  • Operand Stack : 피연산값과 계산과정에서 생기는 중간값을 저장

    • JVM은 Stack기반으로 연산을 수행함
    • 따라서 연산에 필요한 operand가 모두 Stack에 저장되어있기 때문에 Byte Code는 일반적인 어셈블리어와 달리 operand를 지정하지 않아도 연산이 가능하다
    • 다른 어셈블리어와 달리 연산에 레지스터를 쓰지 않은 이유는 각 디바이스마다 레지스터의 수가 달라 그 수를 가정할 수 없기 때문에 하드웨어의 관여를 최소화하기 위해 JVM에서는 연산과정이 복잡하더라도 Stack을 사용한다

만약 쓰레드가 사용할 수 있는 스택의 크기를 넘기게 되면 StackOverflowError 가 발생한다. 또한 스택을 동적으로 확장할 때 확장할 메모리가 부족하거나 새로운 쓰레드 생성 시 스택에 할당할 메모리가 부족하면 OutOfMemoryError 가 발생한다.


PC Register

Stack, Native Method Stack과 함께 쓰레드가 생성될 때 각 쓰레드마다 할당되는 영역으로, 현재 수행중인 JVM의 명령어 주소를 저장한다.

JVM은 Stack-Base방식으로 작동하기 때문에 Stack에서 Operand를 뽑아내에 별도의 메모리 공간에 저장한 다음 연산을 진행하는데, 이때 사용되는 메모리공간이 PC Register이다.

PC Register에는 멀티 쓰레드 프로그래밍 환경에서 한 쓰레드가 작업을 하다가 다른 쓰레드로 CPU자원을 넘겨주고 다시 받았을 때, 이어서 작업을 하기 위해 현재 실행중인 명령어의 주소를 기록한다.

만약 쓰레드가 JVM Instruction을 수행중이라면 Instruction의 주소를 가지고 있지만, Native Method를 수행중이라면 PC Register는 Undefined상태로 남아있고, 이에 대한 처리는 Native Method Stack에서 담당한다


Native Method Stack

Native 언어(C/C++, 어셈블리)로 작성된 코드를 실행하기 위한 메모리 영역

  • 자바 이외의 언어가 JVM에서 동작하기 위해 할당한 메모리 영역으로, 일반적으로 C스택을 사용한다
  • 쓰레드에서 java메소드가 아닌 Native방식을 사용하는 메소드를 실행하면 이 곳에 해당 메소드에 대한 정보를 저장한다
  • JNI(Java Native Interface)를 통해 표준에 가까운 방식으로 구현이 가능하다.

참고자료

0개의 댓글