JAVA

[JAVA] Static, Stack, Heap | Java 메모리 영역의 구조와 특징

제이미로그 2024. 4. 23. 18:30

📌 1. JAVA 의 메모리 구조란?

 

프로그램을 구동하기 위해서는 운영체제(OS)가 메모리(RAM)에 데이터 및 명령어를 저장할 공간을 할당하여 줍니다. 메모리는 컴퓨터에 있어 가장 핵심이 되는 부품이고, CPU가 처리할 데이터가 임시로 저장되는 공간입니다. 동작은 하드디스크에 저장된 데이터가 메모리에 올라가서 실행되며, 메모리(RAM)를 주 기억 장치라고 부릅니다.

메모리는 사용할 수 있는 공간이 한정되어 있기 때문에 어떻게 관리하느냐에 따라서 프로그램의 성능(속도 등)이 좌우됩니다. 따라서 Java 어플리케이션에서 메모리를 효율적으로 사용하기 위해서는 메모리 구조와 특징에 대해 이해할 필요가 있습니다.

 

📌 2. JAVA 의 메모리 구조?

1. Static area(스태틱 메모리 영역) : 객체에 소속된 멤버가 아닌 클래스에 고정된 멤버

 

하나의 JAVA 파일은 크게 필드(field), 생성자(constructor), 메소드(method)로 구성됩니다. 그 중 필드 부분에서 선언된 변수(전역변수)와 정적 멤버변수(static이 붙은 자료형) static 영역에 데이터를 저장합니다. Static 영역의 데이터는 프로그램의 시작부터 종료까지 메모리에 남아있게 됩니다. 

 

static(정적)은 고정된 이라는 의미를 가지고 있습니다. Static 이라는 키워드를 사용하여 Static 변수(정적 필드)와 Static 메서드(정적 메서드)를 만들 수 있는데, 두 가지를 합쳐서 정적 멤버라고 합니다. (= 클래스 멤버) 정적 필드와 정적 메소드는 객체(인스턴스)에 소속된 멤버가 아니라 클래스에 고정된 멤버입니다.

 

Static Area(스태틱 메모리 영역)에 데이터는 프로그램의 시작부터 종료가 될 때까지 메모리에 남아있게 됩니다. 즉, 프로그램이 종료될 때까지 어디서든지 사용이 가능하지만, 주의할 점은 전역 변수를 무분별하게 많이 사용하게 되면 메모리가 부족한 문제가 발생할 수 있습니다. 따라서 필요한 변수만 전역변수로 사용할 필요가 있습니다. 

 

2. Stack area(스택 메모리 영역)  : 메서드 내에서 정의하는 기본 자료형 

메소드 내에서 정의하는 기본 자료형(int, double, byte, long, boolean 등)에 해당되는 지역변수(매개변수 및 블록문 내 변수 포함)의 데이터 값이 저장되는 공간이 Stack 스택 영역입니다. 해당 메소드가 호출될 때 메모리에 할당되고 종료되면 메모리가 해제된다. 

 

기본형 타입 변수의 값들은 Stack 영역에 저장되고, 참조형 타입 변수는 참조값만 저장됩니다. 이 참조값은 아래서 설명한 Heap 영역에 존재하는 인스턴스(객체)를 가르키는 역할을 합니다. (인스턴스의 주소 값)

 

Stack 영역은 LIFO (Last In First Out)의 구조를 갖고 변수에 새로운 데이터가 할당되면 이전 데이터는 지워집니다. 

 

3. Heap Area(힙 메모리 영역)  : 참조형의 데이터 객체에 실제 데이터들이 담기는 공간이고, 실제 데이터를 가지고 있는 Heap 영역의 참조값을 Stack 영역의 객체가 가지고 있는 것.

 

참조형(Reference Type)의 데이터 타입을 갖는 객체, 배열 등은 Heap 영역에 데이터가 저장됩니다. 

* 클래스 변수 = new 클래스(); 를 통해 생성된 객체(인스턴스)

이 때 변수(객체, 객체 변수, 참조 변수) 는 Stack 영역의 공간에서 실제 데이터가 저장된 Heap 영역의 참조값(Reference key, 해시 코드 = 

메모리에 저장된 주소를 연결해주는 값)을 new 연산자를 통해서 리턴 받습니다. 다시 말하면 실제 데이터를 가지고 있는 Heap 영역의 주소값을 Stack 영역의 객체가 갖고 있는 것입니다. 이렇게 리턴 받은 참조값을 가지고 있는 객체를 통해서만 해당 인스턴스를 컨트롤할 수 있습니다. 

 

* 인스턴스의 실제 데이터는 Heap 영역에 올라갑니다.

저장된 메모리의 위치가 다르기 때문에 static 메서드에서 외부 인스턴스 멤버에 접근할 수 없습니다. 

 

 

int a = 10; 이라는 코드를 작성했다면, 정수 값이 할당될 수 있는 메모리 공간을 a라고 잡아두고, 그 메모리 영역에 10이라는 값이 들어갑니다. 즉 Stack 영역의 메모리에 이름을 a라고 붙여주도 값이 10인 메모리 공간을 만드는 것입니다. 

 

User user = new User(); 라는 객체를 생성했다면 user는 Stack 영역에 생성되고, new에 생성된 User 클래스이 인스턴스(실제 데이터)는 Heap 영역에 생성됩니다. 그리고 스택 영역에 생성된 user의 값으로 힙 영역에 있는 실제 데이터 주소의 값을 가지고 있습니다. 

즉, Stack 영역의 user는 Heap 영역의 실제 데이터를 가지고 있는 것입니다.

 

* new를 통해 인스턴스 객체를 생성했을 때, Heap 영역에는 생성된 객체가 올라가고, Stack 영역에는 해당 객체에 대한 주소 값(Reference) 이 저장됩니다. 

 

📌 3. 런타임 데이터 영역(Runtime Data Area)

런타임 데이터 영역은 JVM 의 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역입니다. 

 

모든 스레드가 공유해서 사용(GC의 대상)

- 힙 영역(Heap Area)

- 메서드 영역(Method Area)

 

스레드(Thread)마다 하나씩 생성

- 스택 영역(Stack Area)

- PC 레지스터(PC Register)

- 네이티브 메서드 스택 (Native Method Stack)

 

메서드 영역 (Method Area)

클래스 멤버 변수의 이름, 데이터 타입, 접근 제어자 정보와 같은 각종 필드 정보들과 메서드 정보, 데이터 Type 정보, Constant Pool, static 변수, final class 등이 생성되는 영역입니다. 

 

힙 영역 (Heap Area)

1. new 키워드로 생성된 객체와 배열이 생성되는 영역입니다.

2. 주기적으로 GC가 제거하는 영역입니다. 

 

 

Heap Area는 효율적인 GC를 위해 위와 같이 크게 3가지 영역으로 나뉘게 됩니다. 

 

Young Generation 영역은 자바 객체가 생성되자마자 저장되고, 생긴지 얼마 안되는 객체가 저장되는 공간입니다.  Heap 영역에 객체가 생성되면 최초 Eden 영역에 할당됩니다. 그리고 이 영역에 데이터가 어느 정도 쌓이게 되면 참조 정도에 따라 Servivor의 빈 공간으로 이동되거나 회수됩니다. 

 

Young Generation(Eden+Servivor) 영역이 차게 되면 또 참조 정도에 따라 Old 영역으로 이동 되게 되거나 회수 됩니다. 이렇게 Young Generation과 Tenured Generation에서의 GC를 Minor GC라고 합니다. Old 영역에 할당된 메모리가 허용치를 넘게 되면, Old 영역에 있는 모든 객체들을 검사하여 참조되지 않는 객체들을 한꺼번에 삭제하는 GC가 실행됩니다. 시간이 오래 걸리는 작업이고 이 때 GC를 실행하는 쓰레드를 제외한 모든 스레드는 작업을 멈추게 됩니다. 이를 'Stop - the - World'라고 합니다. 그리고 이렇게 'Stop-the-World'가 발생하고 Old 영역의 메모리를 회수하는 GC를 Major GC라고 합니다. 

 

스택 영역 (Stack Area)

지역변수, 파라미터, 리턴 값, 연산에 사용되는 임시 값 등이 생성되는 영역입니다. 

 

PC 레지스터 (PC Register)

Thread 가 생성될 때마다 생성되는 영역으로 프로그램 카운터, 즉 현재 스레드가 실행되는 부분의 주소와 명령을 저장하고 있는 영역입니다. 

 

네이티브 메서드 스택(Native Method Stack)

1. 자바 이외의 언어(C, C++, 어셈블리 등)로 작성된 네이티브 코드를 실행할 때 사용되는 메모리 영역으로 일반적인 C 스택을 사용합니다. 

2. 보통 C/C++ 등의 코드를 수행하기 위한 스택을 말하며 (JNI) 자바 컴파일러에 의해 변환된 자바 바이트 코드를 읽고 해석하는 것이 자바 인터프리터(interpreter)입니다.