자바 프로그램은 Java Virtual Machine(JVM) 위에서 실행되며, JVM은 프로그램 실행 시 필요한 메모리를 두 가지 주요 영역으로 나누어 관리한다. 바로 스택(Stack)과 힙(Heap)이다. 이 두 메모리 구조는 각각 다른 역할을 수행하며, 자바 애플리케이션의 성능과 안정성에 직접적인 영향을 미친다.
1. 스택 메모리 (Stack Memory)
스택 메모리는 JVM에서 메서드 호출 시마다 생성되며, 메서드 실행에 필요한 지역 변수, 매개변수, 리턴 주소 등을 저장하는 공간이다. 스택은 Last In, First Out(LIFO) 구조를 따르며, 메서드가 호출될 때마다 새로운 프레임(frame)이 생성되고, 해당 메서드가 끝나면 스택 프레임이 제거된다. 이러한 특징 때문에 스택은 매우 빠른 속도로 메모리를 할당하고 해제할 수 있다.스택 메모리의 주요 특징:
- 고정 크기: JVM 시작 시 스택 메모리의 크기가 정해지며, 프로그램 실행 중 변경되지 않는다.
- 메모리 자동 관리: 메서드 호출이 끝나면 자동으로 메모리가 해제된다.
- 작은 메모리 크기: 스택 메모리는 힙보다 크기가 작고, 주로 간단한 데이터나 임시 데이터를 저장하는 용도로 사용된다.
- 쓰레드별 스택: 각각의 쓰레드는 독립적인 스택을 가진다. 따라서, 한 쓰레드의 스택에 있는 데이터는 다른 쓰레드가 접근할 수 없다.
스택 메모리에 저장되는 데이터:
- 기본 자료형: int, float 등과 같은 원시 타입
- 참조 변수: 객체의 실제 데이터는 힙에 저장되지만, 그 참조값(reference)이 스택에 저장된다.
스택 오버플로(Stack Overflow):
스택은 고정된 크기를 가지므로, 무한 재귀 호출이나 너무 많은 메서드 호출이 발생할 경우 스택 오버플로가 발생할 수 있다. 이는 더 이상 사용할 수 있는 스택 메모리가 부족해지면서 프로그램이 비정상적으로 종료되는 상황을 초래한다.
2. 힙 메모리 (Heap Memory)
힙 메모리는 자바에서 동적으로 생성되는 객체들이 저장되는 공간이다. 자바의 모든 객체와 배열은 힙에 저장되며, 해당 객체에 대한 참조는 스택에 저장된 변수를 통해 이루어진다. 힙 메모리는 JVM이 관리하는 영역으로, **가비지 컬렉터(Garbage Collector)**에 의해 주기적으로 불필요한 객체가 정리된다.
힙 메모리의 주요 특징:
- 동적 크기: JVM이 실행되는 동안 필요에 따라 크기가 늘어나거나 줄어들 수 있다.
- 가비지 컬렉션: 객체의 참조가 사라지거나 더 이상 필요하지 않으면 가비지 컬렉터가 해당 메모리를 해제한다.
- 비교적 큰 크기: 스택보다 큰 메모리 공간을 제공하며, 장기적으로 사용되는 데이터나 객체들이 저장된다.
- 공유 메모리: 모든 쓰레드가 같은 힙 영역을 공유하므로, 동기화 문제가 발생할 수 있다.
힙 메모리에 저장되는 데이터:
- 객체: new 키워드를 통해 생성된 모든 객체가 힙에 저장된다.
- 클래스 멤버 변수: 인스턴스 변수는 힙에 저장되며, 이 변수들은 객체가 힙에서 살아있는 한 유지된다.
- 배열: 자바에서 생성되는 배열도 힙에 저장된다.
힙 메모리의 문제점:
- 메모리 누수(Memory Leak): 객체가 필요하지 않음에도 불구하고 참조가 제거되지 않은 경우, 해당 객체가 가비지 컬렉션의 대상이 되지 않아 메모리 누수가 발생할 수 있다.
- OutOfMemoryError: 힙 메모리 공간이 부족해질 경우 더 이상 객체를 생성할 수 없게 되고, 이로 인해 OutOfMemoryError가 발생한다.
3. 스택과 힙의 차이점
스택 | 힙 | |
메모리 크기 | 상대적으로 작다 | 상대적으로 크다 |
메모리 할당 | 정적(고정된 크기) | 동적(필요에 따라 크기가 조정됨) |
메모리 접근 속도 | 빠르다 | 느리다 |
메모리 관리 | 자동 (메서드 종료 시 자동 해제) | 가비지 컬렉션에 의해 관리 |
사용 용도 | 기본 타입 변수, 참조 변수, 메서드 호출 스택 | 객체와 배열, 인스턴스 변수 |
쓰레드 | 각 쓰레드별 독립적인 스택 사용 | 모든 쓰레드가 공유하는 힙 메모리 사용 |
4. 가비지 컬렉션(Garbage Collection)
JVM은 힙 메모리의 효율적인 사용을 위해 가비지 컬렉션(Garbage Collection)을 수행한다. 가비지 컬렉션은 참조되지 않거나 더 이상 사용되지 않는 객체를 힙에서 제거하여 메모리 누수를 방지하고, 힙 메모리의 재사용 가능 공간을 확보하는 역할을 한다. 자바에서는 개발자가 명시적으로 메모리 해제를 처리할 필요가 없으며, JVM이 이를 자동으로 처리해준다.