
안녕하세요.
이번 글에서는 Java에서의 힙 메모리에 대해 공부해보도록 하겠습니다.
저번 포스트였던, 스택 메모리에 이어서 바로 공부를 진행해보도록 하겠습니다.
이번 시간에도 간략하게 정의와 장단점, 그리고 힙 메모리와 차이점을 확인해보며 진행하겠습니다.
Java에서 메모리 관리는 JVM(Java Virtual Machine)에 의해 이루어집니다.
이 중에서도 힙 메모리(Heap Memory)는 Java 프로그램 실행 중 객체를 저장하고 관리하는 중요한 공간입니다.
힙 메모리는 JVM이 런타임 시 동적으로 할당되는 메모리 영역으로, 클래스 인스턴스와 배열이 저장됩니다.
힙 메모리는 다음과 같이 두 가지 영역으로 나눌 수 있습니다.
Young Generation
Eden 영역과 두 개의 Survivor 영역으로 구성됩니다.Old Generation (Tenured Generation)
| 특성 | 힙 메모리 (Heap Memory) | 스택 메모리 (Stack Memory) |
|---|---|---|
| - 저장 내용 | 객체 및 배열 | 메서드 호출 시 생성된 지역 변수 및 메서드 호출 정보 |
| - 할당 방식 | 동적 할당 (Dynamic Allocation) | 정적 할당 (Static Allocation) |
| - 메모리 크기 | 상대적으로 큼 | 상대적으로 작음 |
| - 수명 | GC에 의해 수명이 결정됨 | 메서드 호출이 종료되면 자동으로 해제됨 |
| - 접근 속도 | 상대적으로 느림 | 상대적으로 빠름 |
| - Thread Safety | 멀티스레드 환경에서 동시 접근 가능하지만 동기화 필요 | 각 스레드에 독립적으로 생성되어 동기화 불필요 |
| - 사용 예시 | 클래스 인스턴스, 배열 | 기본 데이터 타입의 지역 변수, 메서드 호출 정보 |
주요 차이점
- 저장 대상: 힙 메모리는 객체와 배열을 저장하고, 스택 메모리는 기본 데이터 타입과 메서드 호출 정보를 저장합니다.
- 관리 방식: 힙 메모리는 GC에 의해 관리되며, 스택 메모리는 메서드 호출이 끝나면 자동으로 메모리가 해제됩니다.
public class MemoryExample {
public static void main(String[] args) {
int localVar = 10; // 스택 메모리에 저장
Person person = new Person("Alice", 25); // 힙 메모리에 저장
System.out.println("스택 변수: " + localVar);
System.out.println("힙 객체: " + person);
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{name='" + name + '\'' + ", age=" + age + '}';
}
}
localVar는 스택 메모리에 저장됩니다.Person 객체는 힙 메모리에 저장되며, person 변수는 스택 메모리에 해당 객체를 참조합니다.localVar는 자동으로 해제되지만, Person 객체는 GC가 해제할 때까지 힙 메모리에 남아 있습니다.| 장점 | 설명 |
|---|---|
| 동적 객체 관리 | 객체와 데이터 구조를 동적으로 관리할 수 있습니다. |
| JVM의 자동 관리 | Garbage Collection으로 메모리를 자동 관리하여 개발자의 부담을 줄입니다. |
| 유연한 크기 | 다양한 크기의 객체를 효율적으로 저장할 수 있습니다. |
| 프로파일링 도구 지원 | VisualVM, JProfiler와 같은 도구를 통해 메모리 사용 상태를 분석하고 최적화 가능합니다. |
| 단점 | 설명 |
|---|---|
| 성능 문제 | GC 실행 중 Major GC는 애플리케이션 성능에 영향을 미칠 수 있습니다. |
| 메모리 누수 위험 | 참조가 제거되지 않은 객체가 메모리를 차지하며 성능 저하를 초래할 수 있습니다. |
| OutOfMemoryError | 설정된 힙 메모리를 초과하면 프로그램이 강제 종료됩니다. |
| 복잡한 튜닝 필요 | GC와 메모리 크기를 적절히 설정하지 않으면 성능 저하가 발생할 수 있습니다. |
아래는 GC 튜닝 옵션을 적용하여 JVM을 실행하는 예제입니다.
GC와 관련된 JVM 옵션은 주로 실행 시 설정되며, 애플리케이션의 성능을 최적화하는 데 사용됩니다.
java -Xms512m -Xmx1024m -XX:NewRatio=2 -XX:+UseG1GC -jar MyApplication.jar
-Xms512m: 힙 메모리 초기 크기를 512MB로 설정-Xmx1024m: 힙 메모리 최대 크기를 1024MB로 설정-XX:NewRatio=2: Young Generation과 Old Generation의 비율을 1:2로 설정-XX:+UseG1GC: G1 Garbage Collector를 사용하도록 설정Java 코드에서 힙 메모리와 관련된 옵션을 설정하려면 ProcessBuilder를 사용할 수 있습니다:
import java.io.IOException;
public class GCOptionsExample {
public static void main(String[] args) throws IOException {
ProcessBuilder processBuilder = new ProcessBuilder(
"java",
"-Xms512m",
"-Xmx1024m",
"-XX:NewRatio=2",
"-XX:+UseG1GC",
"-cp",
"./bin",
"MyApplication"
);
// 프로세스 실행
processBuilder.inheritIO().start();
}
}
ProcessBuilder를 사용하면 특정 JVM 옵션을 설정한 새로운 Java 프로세스를 실행할 수 있습니다.Garbage Collection(GC)은 사용되지 않는 객체를 제거하여 메모리를 회수하는 프로세스입니다.
-Xms: 힙 메모리 초기 크기 설정-Xmx: 힙 메모리 최대 크기 설정-XX:NewRatio: Young Generation과 Old Generation의 비율 설정-XX:+UseG1GC: G1 Garbage Collector 사용ArrayList와 같은 컬렉션의 초기 크기를 적절히 설정합니다.null로 설정하여 GC의 대상이 되게 합니다.힙 메모리는 Java 프로그램에서 중요한 메모리 공간으로,
객체의 생명 주기를 이해하고 최적화하는 것이 성능 개선에 크게 기여할 수 있습니다.
스택 메모리와의 차이점을 이해하고 GC 옵션을 효과적으로 활용해 메모리 문제를 예방해보도록 합시다!
감사합니다.