힙 메모리 이해하기

dakcoh·2024년 9월 27일

안녕하세요.
이번 글에서는 Java에서의 힙 메모리에 대해 공부해보도록 하겠습니다.

저번 포스트였던, 스택 메모리에 이어서 바로 공부를 진행해보도록 하겠습니다.

이번 시간에도 간략하게 정의와 장단점, 그리고 힙 메모리와 차이점을 확인해보며 진행하겠습니다.


Java 힙 메모리 개념 이해

Java에서 메모리 관리는 JVM(Java Virtual Machine)에 의해 이루어집니다.
이 중에서도 힙 메모리(Heap Memory)는 Java 프로그램 실행 중 객체를 저장하고 관리하는 중요한 공간입니다.


힙 메모리란?

힙 메모리는 JVM이 런타임 시 동적으로 할당되는 메모리 영역으로, 클래스 인스턴스와 배열이 저장됩니다.

힙 메모리는 다음과 같이 두 가지 영역으로 나눌 수 있습니다.

  1. Young Generation

    • 새로 생성된 객체가 저장되는 공간으로, Eden 영역과 두 개의 Survivor 영역으로 구성됩니다.
    • 객체가 자주 사용되지 않으면 Garbage Collector(GC)에 의해 제거됩니다.
  2. Old Generation (Tenured Generation)

    • Young Generation에서 오래 생존한 객체가 이동되는 공간입니다.
    • 비교적 적은 빈도로 GC가 실행됩니다.

힙/스택 메모리 비교

특성힙 메모리 (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 + '}';
    }
}

실행 과정

  1. localVar는 스택 메모리에 저장됩니다.
  2. Person 객체는 힙 메모리에 저장되며, person 변수는 스택 메모리에 해당 객체를 참조합니다.
  3. 메서드가 종료되면 localVar는 자동으로 해제되지만, Person 객체는 GC가 해제할 때까지 힙 메모리에 남아 있습니다.

힙 메모리의 장점과 단점

장점

장점설명
동적 객체 관리객체와 데이터 구조를 동적으로 관리할 수 있습니다.
JVM의 자동 관리Garbage Collection으로 메모리를 자동 관리하여 개발자의 부담을 줄입니다.
유연한 크기다양한 크기의 객체를 효율적으로 저장할 수 있습니다.
프로파일링 도구 지원VisualVM, JProfiler와 같은 도구를 통해 메모리 사용 상태를 분석하고 최적화 가능합니다.

단점

단점설명
성능 문제GC 실행 중 Major GC는 애플리케이션 성능에 영향을 미칠 수 있습니다.
메모리 누수 위험참조가 제거되지 않은 객체가 메모리를 차지하며 성능 저하를 초래할 수 있습니다.
OutOfMemoryError설정된 힙 메모리를 초과하면 프로그램이 강제 종료됩니다.
복잡한 튜닝 필요GC와 메모리 크기를 적절히 설정하지 않으면 성능 저하가 발생할 수 있습니다.

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 프로세스를 실행할 수 있습니다.
  • 이 방식은 JVM 옵션을 실험적으로 변경하고 애플리케이션의 성능을 비교하는 데 유용합니다.

힙 메모리와 Garbage Collection

Garbage Collection(GC)은 사용되지 않는 객체를 제거하여 메모리를 회수하는 프로세스입니다.

  • Minor GC: Young Generation에서 주로 발생하며, 속도가 빠릅니다.
  • Major GC: Old Generation에서 발생하며, 더 많은 메모리를 회수하지만 시간이 더 걸립니다.

GC 프로세스

  1. 객체 생성: Eden 영역에 객체가 생성됩니다.
  2. 생존 객체 이동: Eden 영역에서 살아남은 객체는 Survivor 영역으로 이동합니다.
  3. Old Generation 이동: Survivor 영역에서 일정 시간 생존한 객체는 Old Generation으로 이동합니다.

주요 GC 튜닝 옵션

  • -Xms: 힙 메모리 초기 크기 설정
  • -Xmx: 힙 메모리 최대 크기 설정
  • -XX:NewRatio: Young Generation과 Old Generation의 비율 설정
  • -XX:+UseG1GC: G1 Garbage Collector 사용

힙 메모리 최적화 팁

  • 필요한 객체만 생성하기: 불필요한 객체 생성을 피합니다.
  • 컬렉션 크기 초기화: ArrayList와 같은 컬렉션의 초기 크기를 적절히 설정합니다.
  • 참조 해제하기: 사용이 끝난 객체의 참조를 null로 설정하여 GC의 대상이 되게 합니다.
  • 프로파일링 도구 활용: VisualVM, JProfiler 등 도구를 사용하여 메모리 사용을 분석합니다.
  • JVM 옵션 튜닝: 애플리케이션에 적합한 힙 크기 및 GC 옵션을 설정합니다.

마무리

힙 메모리는 Java 프로그램에서 중요한 메모리 공간으로,
객체의 생명 주기를 이해하고 최적화하는 것이 성능 개선에 크게 기여할 수 있습니다.

스택 메모리와의 차이점을 이해하고 GC 옵션을 효과적으로 활용해 메모리 문제를 예방해보도록 합시다!

감사합니다.

관련글 > 스택 메모리 이해하기

profile
포기하기 금지

0개의 댓글