먼저, 힙과 스택의 구조부터 알아보자.

+-------------------------+
|    Method Area          |  클래스 정보, static 변수
+-------------------------+
|         Heap            |  new로 생성한 객체 저장
| (모든 스레드 공유)       |
+-------------------------+
|       Stack (Thread 1)  |  메서드 호출마다 Frame 생성
| - 메서드 Frame           |  지역변수, 파라미터
| - 메서드 Frame           |  리턴 주소 등
+-------------------------+
|       Stack (Thread 2)  |  스레드마다 별도 Stack
| - 메서드 Frame           |
+-------------------------+
|     PC Register         |  현재 실행 중인 명령어 주소
| (스레드별)               |
+-------------------------+
| Native Method Stack     |  JNI 호출용
+-------------------------+

 

  • Heap: 객체(인스턴스) 저장 (공용 영역)
  • Stack: 메서드 호출 정보 저장 (스레드 프라이빗)

 


OOME, OutOfMemoryError

Java의 Heap 공간은 거의 모든 객체와 인스턴스가 저장되는 영역이다.

그러나 무한 루프 안에서 객체를 계속 생성하거나,

대규모 컬렉션(List, Map 등)을 관리하면서 참조를 끊지 않게 되면,

GC(Garbage Collector)가 불필요한 객체를 수거하지 못해 Heap 공간이 고갈된다.

이럴 때 OutOfMemoryError(OOME)가 발생한다.

 

대표적인 상황은

  • 무한 객체 생성
  • 캐시(메모리)에 데이터 무한 적재
  • 참조 해제 없이 객체를 쌓아두는 메모리 누수(Leak)

다음 코드 예시를 살펴보자.

import java.util.ArrayList;
import java.util.List;

public class OOMExample {
    public static void main(String[] args) {
        List<byte[]> list = new ArrayList<>();
        while (true) {
            list.add(new byte[10 * 1024 * 1024]); // 10MB 배열 계속 추가
        }
    }
}

 

위 코드는 10MB 짜리 byte 배열을 무한히 리스트에 추가하는 코드이다.

결국 GC가 치우지 못하고 Heap이 가득 차게 되면서 java.lang.OutOfMemoryError: Java heap space 가 발생한다.


SOE, StackOverflowError

Stack 영역은 각 스레드 프라이빗(스레드의 지역변수같은 느낌)하며,

하나의 스레드 안에서 발생하는 메서드 호출과 지역변수를 관리한다.

메서드가 호출될 때마다 Stack Frame이 쌓이는데,

이 호출이 탈출 조건 없이 무한 반복되거나,

메서드 호출 깊이가 지나치게 깊어지면 Stack 크기를 초과하여

StackOverflowError(SOE)가 발생한다.

 

대표적인 상황은

  • 탈출 조건이 없는 재귀 호출
  • 너무 깊은 메서드 체인 호출
  • 의도치 않은 순환 호출(loop)

다음 예시 코드를 살펴보자.

public class SOEExample {
    public static void main(String[] args) {
        recursiveMethod();
    }

    private static void recursiveMethod() {
        recursiveMethod(); // 탈출 조건 없는 재귀 호출
    }
}

 

 

위 코드는 recursiveMethod()가 끝나지 않고 자기 자신을 계속 호출하는 코드이다.

Stack Frame이 무한히 쌓이다가 Stack 공간을 초과하게 되면서, java.lang.StackOverflowError 가 발생한다.

 


정리

구분 OutOfMemoryError StackOverflowError
발생 위치 Heep or Method Area 등 Stack
원인 객체를 너무 많이 생성해서 Heap 공간 부족 메서드 호출이 너무 깊어져 Stack 공간 초과
대표 상황 - 무한 객체 생성
- 메모리 누수(Leak)
- 재귀 호출 무한 루프
- 메서드 깊이 너무 깊음
해결 방법 - GC 튜닝
- 객체 수명 관리
- Heap 사이즈 조정
- 재귀 줄이기
- 코드 개선
- Stack 사이즈 조정
에러 메시지 java.lang.OutOfMemoryError java.lang.StackOverflowError

 

+ Recent posts