[Java를 실행하면 어떻게 진행이 되나요?] 2-3. JVM-Run Time Data Area

khyojun·2022년 11월 30일
2
post-thumbnail

🔍 Java 실행 과정

오늘은 3번째 Runtime Data Area에 대해서 알아보자.

  • ✔ Class Loader
  • ✔ Execution Engine
  • Runtime Data Area
  • GarbageCollector

🔍 Runtime Data Area

JVM의 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 저장하는 곳이다. 이를 그림처럼 5가지로 나눠서 본다.

  • Method Area
  • Heap Area
  • Stack Area
  • Pc register
  • Native Method Stack

📌 Method Area

Method Area에는 정적 변수를 포함하여 클래스 이름, 직계 부모 클래스 이름, 메서드 및 변수 정보 등 모든 클래스 수준 정보가 저장됩니다. JVM당 하나의 메소드 영역만 있으며 공유 자원입니다. Java 8부터 정적 변수는 이제 Heap Area에 저장됩니다.
그리고 Method Area는 인스턴스 생성을 위한 객체 구조, 생성자, 필드 등이 저장되고, Runtime Constant Pool, static 변수, 메소드 데이터와 같은 Class 데이터들도 이곳에서 관리가 됩니다.

요약하면

간단하게 말하자면 클래스와 관련된 모든 정보가 저장이 된다는 것이다.

단 하나만!

그래서 이러한 중요한 정보들이 다 있기에 JVM은 단 하나의 Method Area만 가진다고 한다.

공유도 😁😅

위 설명에서 말한대로 Method Area에서는 인스턴스 생성에 대한 정보들도 있어서 JVM의 모든 Thread 들이 Method Area를 공유하게 된다.
ex) 같은 JVM의 다른 메모리 영역에서의 정보 요청 -> 실제 물리 메모리 주소를 변환해서 전달

생존범위

그래서 이 메서드 Method Area에서는 너무 중요한 정보들도 많고 기초적인 정보들도 많기에 JVM 구동 시작 시에 생성이 되서, 종료 때까지 유지되는 공통되는 영역이라고 불린다!
그래서! Method(Static) 영역에 있는 데이터는 프로그램의 시작부터 종료가 될 때까지 메모리에 남아있다.😅

📌 Heap Area

Heap 영역은 코드 실행을 위한 Java 로 구성된 객체 및 JRE 클래스들이 탑재됩니다. 이곳에서는 문자열에 대한 정보를 가진 String Pool 뿐만이 아니라 실제 데이터를 가진 인스턴스, 배열 등이 저장이 됩니다.
메소드 영역에 로드된 클래스만 생성이 가능하고 Garbage Collector가 참조되지 않는 메모리를 확인하고 제거하는 영역입니다.

요약하면

이것도 간단하게 말하면 모든 객체의 정보가 Heap 영역에 저장이 된다고 한다. 그리고 참조되지 않는 메모리를 Garbage Collector가 찾아서 제거해준다고 한다.

이것도 단 하나만!

이것도 모든 객체의 정보가 저장이 되기에 단 하나만 존재를 한다고 한다.

공유도 😁😅

마찬가지로 단 하나만 존재하기에 Heap 영역이 가진 데이터는 모든 Java Stack 영역에서 참조가 되서, Thread간 공유가 된다.

생존범위

메모리가 호출이 끝나더라도 삭제되지 않고 유지된다.

OutOfMemoryError

Heap 영역이 가득 차게 되면 OutOfMemoryError를 발생시키게 된다. 즉 객체를 생성하려하는데 그럴 수 있는 공간이 없으면 발생하는 것이다.

Heap은 여기서 끝이 아니다!

위 설명에 있는대로 Heap영역에서 주로 Garbage Collector가 동작하게 된다. 그에 대한 설명은 Garbage Collector와 더 관련이 있기에 다음 글에서 더 세세하게 설명하도록 하겠다.

📌 Stack Area

모든 스레드에 대해 JVM은 여기에 저장되는 하나의 런타임 스택을 생성합니다. 이 스택의 모든 블록은 메서드 호출을 저장하는 활성화 레코드/스택 프레임이라고 합니다. 해당 메서드의 모든 지역 변수는 해당 프레임에 저장됩니다. 스레드가 종료된 후 런타임 스택은 JVM에 의해 파괴됩니다. 공유 리소스가 아닙니다.
각 Thread 별로 따로 할당되는 영역입니다. Heap 메모리 영역보다 비교적 빠르다는 장점이 있습니다. 또한, 각각의 Thread 별로 메모리를 따로 할당하기 때문에 동시성 문제에서 자유롭다는 점도 있습니다.

요약하면?

메소드 내에서 정의하는 기본 자료형에 해당되는 지역변수의 데이터 값이 저장되는 공간, 메서드 마다 따로 생성, 각 스레드마다 따로 할당이 된다. 그렇기에 빠르다. 따로 따로 할당받기 때문에 동시성 문제에서 자유롭다!

공유도😁

공유 리소스는 아니다.

생존 범위

메소드가 호출 될 때 메모리에 할당되고 종료되면 메모리에서 사라짐

동작 과정

각 Thread 들은 메소드를 호출할 때마다 Frame 이라는 단위를 추가(push)하게 됩니다. 메소드가 마무리되며 결과를 반환하면 해당 Frame 은 Stack 으로부터 제거(pop)가 된다.

Frame은 뭘 가지고 있나?

Frame 은 메소드에 대한 정보를 가지고 있는 Local Variable, Operand Stack 그리고 Constant Pool Reference 로 구성이 되어 있습니다.

  • Local Variable: 메서드 안의 지역 변수들을 가지고 있다.
  • Operand Stack: 메서드 내 연산을 위한 바이트 코드 명령문들이 들어있는 공간.

StackOverFlowError 낯설지 않은 이 느낌..

Java Stack 영역이 가득 차게 되면 StackOverFlowError 를 발생시키게 된다. 그런데 JVM의 전체적인 메모리가 부족하면 OutOfMemoryError가 발생하기도 한다.
그러면 어떨 때 생길까? Frame이 쌓인다고 했는데 그럼 메서드를 많이 부르면 생기지 않을까?
아래의 코드는 재귀 함수를 통해서 끊임없이 func()함수를 부른다.

public class Stack {
    
    public static void main(String[] args) {
        System.out.println("Stack 메모리 오류");
        try{
            int num = func(0);
        } catch (Error e) {
            System.out.println(e);
        }
    }

    private static int func(int num) {
        num = num+1;
        return func(num);
    }
}

이렇게 func()이 1,2,3,4,5,6 무한하게 불려지면 쌓여지는 stack의 범위를 초과해 StackOverFlowError가 생긴다고 한다.

📌 PC(Program Counter) Registers

Java 에서 Thread 는 각자의 메소드를 실행하게 됩니다. 이때, Thread 별로 동시에 실행하는 환경이 보장되어야 하므로 최근에 실행 중인 JVM 에서는 명령어 주소값을 저장할 공간이 필요합니다. 이 부분을 PC Registers 영역이 관리하여 추적해주게 됩니다.

요약하면

Thread(쓰레드)가 생성될 때마다 생성되는 영역으로 Program Counter 즉, 현재 쓰레드가 실행되는 부분의 주소와 명령을 저장하고 있는 영역이다.
이것을 이용하기에 쓰레드를 돌아가면서 수행할 수 있게 한다.

📌 Native Method Stacks

Java 로 작성된 프로그램을 실행하면서, 순수하게 Java 로 구성된 코드만을 사용할 수 없는 시스템의 자원이나 API 가 존재합니다. 다른 프로그래밍 언어로 작성된 메소드들을 Native Method 라고 합니다. Native Method Stacks 는 Java 로 작성되지 않은 메소드를 다루는 영역입니다. C Stacks 라고 불리기도 합니다. 앞의 Java Stacks 영역과 비슷하게 Native Method 가 실행될 경우 Stack 에 해당 메서드가 쌓이게 됩니다. 각각의 Thread 들이 생성되면 Native Method Stacks 도 동일하게 생성이 됩니다.

요약하면

순수하게 Java로 구성된 코드로 사용할 수 없는 자원이나 API를 사용하기 위해 다른 프로그래밍 언어로 작성된 메서드들을 Native Method라고 한다. 즉, Java로 작성되지 않은 메서드를 다루는 영역이다.

이름에 Stack?

이름에 Stack이 작성되어있는데 Java Stack 영역과 비슷하게 Native Method가 진행이 되어도 Stack에 해당하는 메서드가 생성이 된다고 한다. 각 Thread마다 Stack이 생기는 것도 기존의 Stack 영역과 같다.

JVM 기능 정리 글

  • ✔ Class Loader
  • ✔ Execution Engine
  • ✔ Runtime Data Area
  • Garbage Collector

출처

profile
코드를 씹고 뜯고 맛보고 즐기는 것을 지향하는 개발자가 되고 싶습니다

0개의 댓글