[Java] JVM 메모리 영역 | Method Area, Heap, Stack, PC register, Native Method Stack

dyomi·2024년 7월 4일

자바 컴파일 과정은 이전 포스팅 참고
[Java] 자바 컴파일 과정 | class loader, jvm, compiler, interpreter

JVM 메모리 영역은,

런타임 데이터 영역이라고 불리면서, 자바 프로그램을 실행하는 동안 필요한 데이터를 저장하고 관리하는 공간이다.

1. Method Area

메서드 영역은 JVM이 시작될 때 생성되는 공간으로 바이트 코드(.class)를 처음 메모리 공간에 올릴때 초기화되는 대상을 저장하기 위한 메모리 공간이다.

JVM이 동작하고 클래스가 로드될 때 적재돼서 프로그램이 종료될 때까지 저장된다.

모든 쓰레드가 공유하는 영역이며, 간단히 말하면 정적 필드와 클래스 구조만을 갖고 있는 공간이라 할 수 있다.

2. Heap Area

힙 영역은 new 연산자로 생성되는 인스턴스 변수나 배열 등 참조 자료형이 저장되는 공간으로 다른 스택 영역에서 해당 힙 영역의 변수를 참조하는 구조인데, 이때 참조하는 변수나 필드가 없다면 가비지 컬렉터에 의해 제거된다.

이 힙 영역은 메서드 영역과 마찬가지로 모든 쓰레드가 공유하는 영역이다.

힙 내부 구조는 아래의 그림과 같이 나뉘게 되며, 이는 가비지 컬렉터에 관한 장에서 다시 설명하겠다.

[Java] Garbage Collector 동작 원리와 과정 | Heap Memory, Minor/Major GC, GC algorithm

3. Stack Area

스택 영역은 메서드 호출시마다 각각의 스택 프레임이 생성되고, 현재 실행중인 메서드 안에서 사용되는 값들을 저장하는 영역이다.

여기서 스택 프레임은 JVM 스택에 저장되는 구조체로, 각 메서드 호출 시 하나의 스택 프레임이 생성되어 JVM 스택에 푸시(push)된다.
이 스택 프레임에 메서드 실행에 필요한 모든 정보가 포함된다.

메서드 반환시, 현재 스택 프레임이 JVM 스택에서 팝(pop)되며, 반환 값이 있을 경우 상위 스택 프레임에 반환이 된다.

예외가 발생할 경우 현재 스택 프레임에서 예외 처리를 할 수 있는 핸들러를 찾고, 만약 없을 경우, 상위 스택 프레임으로 예외가 전파된다.

이때 printStackTrace()등의 메서드로 보여주는 Stack Trace의 각 라인은 하나의 스택 프레임을 표현한다.

스택 트레이스(Stack Trace)란 무엇일까?

스택 트레이스는 프로그램의 실행 과정에서 호출된 메서드들의 순서와 위치 정보를 나타내는 것이다.

스택 트레이스는 일반적으로 예외가 발생했을 때, 예외가 발생한 위치부터 시작해 메서드 호출의 역순으로 나열된다.

이러한 스택 영역은 각 쓰레드마다 하나씩 존재하며, 쓰레드가 시작될 때 할당된다.

프로세스가 메모리에 로드될 때 스택 사이즈가 고정되어 있어, 런타임 시에는 스택 사이즈를 바꿀 수 없다.

만약 프로그램 실행 중 메모리 크기가 충분하지 않다면 StackOverFlowError가 발생하게 된다.

StackOberFolowError 발생 원인은 다음과 같다.

  1. 무한 재귀 호출
public class StackOverflowExample {
    public static void recursiveMethod() {
        recursiveMethod(); // 무한 재귀 호출
    }

    public static void main(String[] args) {
        recursiveMethod();
    }
}
  1. 깊은 메서드 호출 체인
public class StackOverflowExample {
    public static void method1() {
        method2();
    }

    public static void method2() {
        method3();
    }

    public static void method3() {
        method4();
    }

    public static void method4() {
        method1(); // 이 패턴이 계속되면 결국 스택 오버플로우가 발생할 수 있음
    }

    public static void main(String[] args) {
        method1();
    }
}

4. PC Register (Program Counter Register)

PC 레지스터는 쓰레드가 시작될 때 생성되며, 현재 수행중인 JVM 명령어 주소를 저장하는 공간이다.

멀티쓰레드 환경에서 CPU 점유를 넘겨주었다가 다시 돌아올 때 하고 있던 일을 기억하기 위해 저장한다.

만약 자바가 아닌 다른 언어(C언어, 어셈블리)의 메서드를 수행하고 있다면, undefined 상태가 된다.

왜나하면 자바에서는 이 두 경우를 따로 처리하기 때문이다.

이 부분은 바로 아래에서 설명하는 Native Method Stack 공간이다.

5. Native Method Stack

네이티브 메서드 스택은 자바의 바이트 코드가 아닌, 다른 언어로 작성된 메서드를 담아두는 공간이다.
예를 들어 JIT 컴파일러에 의해 변환된 네이티브 코드 역시 이 공간에서 실행된다고 볼 수 있다.



🌟 추가 질문

📍 그렇다면 이 5가지의 메모리 영역 중 개발자에게 있어 가장 중요하고 꼭 알고 있어야 하는 영역을 꼽자면 어느 부분일까?

아무래도 힙(Heap) 영역스택(Stack) 영역이라고 볼 수 있다.

이 두 영역은 자바 프로그램의 성능, 메모리 사용, 디버깅 등에 있어 중요한 역할을 하며, 이 부분을 이해하는 것은 자바 애플리케이션 개발에 필수적이라 볼 수 있다.

우선 힙영역은 모든 객체와 배열이 저장되므로, 객체 생성과 메모리 관리에 직결된다. 추가로 메모리 누수를 방지하고 효율적인 메모리 사용을 위해서 GC의 동작을 이해하는 것도 중요하다.
힙 크기와 GC 설정은 애플리케이션의 성능에 큰 영향을 미치고, JVM 옵션을 통해 힙 크기와 GC 정책을 조정하여 성능을 최적화 할 수 있다.

스택 영역은 메서드 호출과 관련된 모든 정보가 스택에 저장되므로, 호출 관계와 실행 흐름을 이해하는데 필수적이다.
메서드의 지역 변수와 매개변수가 스택에 저장되므로, 변수의 생명 주기와 스코프를 이해하는 데 중요하며, 재귀 호출이나 깊은 메서드 호출로 인해 StackOverflowError가 발생할 수 있으므로 이를 예방하고 디버깅하는데 도움이 된다.



참고자료
JVM 내부 구조 & 메모리 영역 💯 총정리

profile
기록하는 습관

0개의 댓글