Runtime Data Area

2023. 2. 3. 18:06JAVA

Runtime Data Area 란?

  • Process 로서, JVM 이 프로그램을 수행하기 위해 OS 로부터 할당 받는 메모리 영역
  • 각각의 목적에 따라 5개의 영역으로 나뉜다
    • PC Register
    • JVM Stack
    • Native Method Stack
    • Method Area
    • Heap
  • Register, JVM Stack, Native Method Stack 은 스레드별로 생성되고 Method Area와 Heap 영역은 모든 스레드에게 공유된다

각 영역과 스레드

PC Register

  • 레지스터란, CPU가 1+2 라는 연산을 수행할 때, 연산을 수행하기 위해 1, +, 2 라는 데이터를 잠깐 저장해놔야하는데 이 때 사용되는 저장공간이다.
  • 하지만 PC Register 는 저런 레지스터와 다르다.
  • JVM은 CPU에 직접 연산을 수행하지 않고 연산 데이터를 별도의 메모리로 저장하는데 이것이 PC Register 이다
  • 앞에서 말한 레지스터는 특정 CPU에 종속된 것이지만 JVM은 플랫폼에 독립적이어야 한다.
  • JVM도 OS나 CPU 입장에서는 하나의 프로세스에 지나지 않기 때문에 머신의 리소르를 사용하는 것은 당연하다
  • 그래서 JVM은 연산을 CPU에 제공해야하고, 이를 위한 버퍼 공간으로 PC Register 라는 메모리 영역을 만든 것이다.
  • 또한 PC Register는 현재 스레드의 연산의 주소를 가지고 있어서 멀티 스레드 환경에서 컨텍스트 스위칭이 일어날때 스레드 정보를 저장하여 다시 해당 스레드가 수행될 때, 저장한 위치에서 이어서 실행할 수 있다.

JVM Stack

    • 스레드의 수행 정보를 기록하는 프레임을 저장하는 메모리 영역
    • 각 스레드별로 생성되기 때문에 동기화 이슈가 없다( 예) 로컬 변수 )

  • 현재 수행중인 Stack Frame 을 Current Frame 이라고 한다
  • 스레드가 메소드를 하나 수행하면 JVM은 Stack Frame 을 하나 생성하여 JVM Stack 에 Push 한다
  • 메소드가 수행을 마치면 Pop 하여 JVM Stack 에서 제거 되고 이전의 Stack Frame 이 Current Frame 이 된다
  • 메소드 수행중 Exception이 발생하면 예외처리 후 JVM Stack 에서 Pop 된다

Stack Frame

  • 스레드가 수행하고 있는 어플리케이션을 메소드 단위로 기록하는 곳
  • Local Variable Section, Operand Stack, Frame Data  세 부분으로 구성
  • Stack Frame 의 크기는 컴파일 시점에 정해진다

Local Variable Section

    • 메소드의 파라미터 변수, 로컬 변수가 저장된다
    • 0부터 시작하는 인덱스를 가진 Array 로 구성된다

  • 파라미터 변수는 선언된 순서로 인덱스가 할당 된다
  • 로컬 변수는 컴파일러가 알아서 인덱스를 할당한다. 만약 사용되지 않는 변수라면 인덱스를 할당하지 않을 수 있다
  • 원시타입 변수는 고정된 크기로 할당된다
  • 객체는 Heap 에 저장되고 Local Variable Section 에서는 객체의 주소만 저장한다.
  • 따라서 원시타입과 래퍼타입 중에 래퍼타입을 사용하면 Heap을 찾아가야하므로 더 많은 CPU나 메모리를 사용하여 성능에 좋지 않다
  • char, byte, short, boolean  형으로 선언된 변수는 Local Variable Section 에서는 int 형으로 할당 된다
  • 이 중에서 char, byte, short 는 Heap 등 다른 곳에서는 원래의 형으로 원복하여 저장한다
  • boolean 은 Heap이나 다른 메모리 영역에도 int 로 저장된다.
  • long, double 형은 대형 타입이기 때문에 두 개의 엔트리를 차지하며 연속되게 저장된다
  • 0번 인덱스는 로컬 메소드나 인스턴스 메소드에 무조건 포함되는 Heap 에 있는 객체의 주소를 저장하고 있다
  • 클래스 메소드 즉, static 으로 선언한 메소드는 hidden this 가 존재하지 않는다

Operand Stack

    • JVM이 프로그램을 수행하면서 연산을 위해 사용되는 데이터 및 그 결과를 이 Operand Stack 에 넣고 처리한다.
    • 연산을 위해 Instruction이 순서대로 Push 되면 이 값을 Pop 하여 연산처리한다.

예제 코드

  • Local Variable Section 에 선언한 로컬변수 a,b,c 에 대한 공간이 생기고 값이 할당 된다
  • Operand Stack이 Local Variable Section 에 저장된 값들을 꺼내서 연산에 사용하고 결과를 다시 Local Variable Section 에 저장한다

Frame Data

  • Constant Pool Resolution 정보, Method 가 정상 종료했을 때의 정보, 비정상 종료 했을 시 Exception 관련 정보를 저장한다
  • Resolution 은 Symbolic Reference 를 Direct Reference 로 변경하는 과정
  • Class 의 모든 Symbolic Reference 는 Method Area 의 Constant Pool 이라는 곳에 저장되어 있기 때문에 Resolution 을 Constant Poll Resolution 이라고 한다
  • 즉 Constant Pool 의 Pointer 정보를 저장하고 필요할때마다 Pointer 를 참조하여 Constant Pool 을 찾아간다
  • 메소드가 정상 종료 했을 때, 자신을 호출한 Stack Frame의 Instruction Pointer 를 PC Register 에 설정하고 Stack Frame을 빠져나간다
  • 만약 메소드가 종료될 때 return 값이 있다면 해당 값을 자신을 호출한 메소드의 Stack Frame 의 Operand Stack 에 Push 하는 작업도 병행한다
  • Frame Data에서 Exception 정보를 가지고 있고 Class File 은 Exception table 을 가지고 있는데 Exception 이 발생하면 이를 참조하여 catch 절에 해당하는 Bytecode로 점프하게 된다

Native Method Stack

    • Java 는 Java 외의 언어로 작성된 프로그램, API 등과의 통합을 쉽게 하기 위하여 JNI 라는 표준 규약을 제공하고 있다
    • 다시 말해 Native Code 로 되어 있는 Function 의 호출을 Java 프로그램 내에서 직접 수행할 수도 있고 그 결과 값을 받아 올 수도 있다
    • JVM 은 Native Method 를 위해 Native Method stack 이라는 메모리 공간을 마련하였다.
    • 동작하는 방식은 JVM Stack 과 유사하다
    • 언어 별로 스택이 생성되어 수행된다.

  • 약간 특이한 점은 Native Function이 모두 수행되고 자신을 호출한 JVM Stack의 Stack Frame 으로 돌아가는 것이 아니라 새로운 Stack Frame 을 생성하여 이어서 진행한다
  • Hotsot JVM 이나 IBM JVM 모두 JVM Stack 과 Native Method Stack 을 구분하지 않는다 ( Native Method Stack 으로 통합됨)
  • 초기 자바에서는 OS 가 관리하는 Native Thread 를 사용한 것이 아니라 JVM 이 생성하고 관리하는 Green Thread 만을 사용하였다
  • 하지만 Green Thread 가 Native Thread 로 전환하기 시작하였고 작업 공간도 Native Stack 으로 통합되어 사용하게 되었다
  • 스택이 통합되었다고 해도 JVM Stack 이 하던 작업 내용이나 방식은 달라진 것이 없다

Method Area

  • Load 된 Type 을 저장하는 논리적 메모리 공간. 여기서 Type 이란 Class 나 Interface 를 의미
  • 모든 스레드들이 공유하는 메모리 영역
  • Type의 Bytecode, 모든 변수, 상수, Reference, 메소드 정보 등을 저장한다
  • ClassLoader 에게 넘겨 받은 Class File 에서 Type 관련 정보를 추출하여 저장한다

Type Information

 

 

 

 

 

 

 

 

 

 

  • 정리하면 타입의 종류, 타입명, 타입의 Modifier 등 타입의 정보를 저장

Constant Pool

  • Type 의 모든 Constant 정보를 가지고 있다
  • 여기서 Constant 는 상수의 의미만 가지고 있는것이 아니다. 상수의 의미를 지닌 Literal Constant 는 물론이고 Type, Field(멤버 변수, 클래스 변수), Method 로의 모든 Symbolic Reference 까지 확장한 개념
  • JVM 은 실행 시 참조하는 객체에 접근할 필요가 있으면 Constant Pool 의 Symbolic Reference 를 통해 해당 객체가 위치한 메모리의 주소를 찾아 동적으로 연결하게 된다

Field Information

  • Type 에서 선언된 모든 Field 의 정보를 저장
  • 선언된 순서대로 기록된다
  • Field 이름, Field 의 Data Type, 선언된 순서, Field 의 Modifier (public, private, protected, static, final, vlatile, transient)

Method Information

  • Type 에서 선언된 모든 Method 정보를 저장

 

 

 

 

 

 

 

 

 

 

 

Class Variable

  • Class 에서 static 으로 선언된 변수이며 Class 에서는 하나의 값으로 유지
  • 모든 객체에 공유되기 때문에 동기화 이슈 발생
  • 객체가 없어서 접근 가능
  • Class 를 사용하기 전부터 Method Area 에 미리 메모리를 할당 받는다
  • Class Variable 을 final 로 선언할 경우에는 이를 변수로 취급하는 것이 아니라 상수로 취급하여 Constant Pool 에 Literal Constant 로 저장 된다

Reference to Class ClassLoader

  • Type 이 User-Defined ClassLoader 를 통해 로딩된 경우는 ClassLoader 의 Reference 를 Type 의 정보 중 하나로 저장하게 된다
  • Bootstrap ClassLoader 의 경우는 Reference 가 null 로 저장된다
  • 이 정보는 Dynamic Linking 을 할 때 해당 Type 과 동일한 ClassLoader 를 통해 참조하는 Type 을 로딩하기 위해 사용된다

Reference to Class class

  • Type 이 JVM 에 Load 되면 항상 java.lang.class class 의 Instance 가 하나 생성된다
  • Method Area 에는 Type 정보의 일부로 이 Instance 의 Reference 를 저장한다
  • getName() 을 통해 Class 이름을 알아오거나 isInterface() 를 통해 인터페이스 여부 등을 알 수 있는 것도 class 인스턴스의 Reference 를 통하기 때문이다

Method Table

    • 자바는 프로그램 수행 중에 Reference 를 통해 객체를 찾아 다니는 일이 빈번하게 발생한다
    • 따라서 원하는 객체를 찾는 속도는 성능의 중요한 이슈가 된다
    • 그래서 Method Table 이라는 데이터 구조를 사용한다
    • Method Table 은 한마디로 Class 의 메소드에 대한 Direct Reference 를 갖는 자료 구조라고 할 수 있다

  • 예제 처럼 Class B 가 부모 클래스인 Class A 의 a2 메소드를 참조하면, Class B 의 Method Table 에서 바로 Heap에 있는 부모 객체의 주소를 알 수 있다
  • (Method Table 이 없다면 Class B 의 Method Area 에서 부모 클래스인 Class A 를 찾고, Class A의 Method Area 로 가서 적당한 객체를 찾아야한다)

Heap

  • Instance 또는 Array 객체 두 가지 중료만 저장되는 공간
  • 모든 스레드들에 의해 공유된다
  • 같은 어플리케이션을 사용하는 스레드 사이에는 공유된 힙 데이터를 이용할 때 동기화 이슈가 발생한다

Object Layout

Object 와 Array 는 모두 Header 와 Data 로 나위어져 있다

'JAVA' 카테고리의 다른 글

로그 찍을 때, 값을 파라미터로 넘겨야하는 이유  (0) 2021.04.05
JAVA Collection - List 시간 복잡도  (0) 2021.02.17
parseInt와 valueOf의 차이점  (0) 2021.01.16
Optional이란?  (0) 2021.01.16
자바8, 스트림  (0) 2021.01.15