메모리 관리 Java

⚡ 스마트 요약

메모리 관리 Java JVM이 런타임 메모리를 스택, 힙 등으로 어떻게 나누는지 설명합니다. Code또한 정적 영역, 메서드 호출 중 객체 참조의 흐름 방식, 그리고 가비지 컬렉터가 도달할 수 없는 객체를 회수하여 애플리케이션이 안정적으로 유지되고 메모리 누수가 발생하지 않도록 하는 방법에 대해서도 설명합니다.

  • 🧠 JVM 메모리 레이아웃: Java 메모리는 객체를 위한 힙, 메서드 프레임과 지역 변수를 위한 스택, 그리고 바이트코드와 정적 데이터를 위한 전용 영역으로 나뉩니다.
  • 📚 스택 vs 힙: 스택 프레임은 후입선출(LIFO) 순서를 따르며 기본 데이터 유형과 참조를 저장하는 반면, 힙은 new 연산자로 생성된 모든 객체를 저장합니다.
  • ♻️ 쓰레기 수거: 가비지 컬렉터 tracks는 참조 체인을 통해 도달 가능성을 확인하고, 어떤 스레드도 도달할 수 없는 객체로부터 메모리를 자동으로 회수합니다.
  • 현대 수집가들: 실제 운영 환경에서는 수 기가바이트에 달하는 대용량 메모리에서 지연 없는 데이터 수집을 위해 G1, ZGC, Shenandoah와 같은 기술에 대한 의존도가 점점 높아지고 있습니다.
  • 🧪 실제 사례: 학생 클래스에 대한 단계별 설명은 참조가 언제 컬렉션 대상이 되는지, 그리고 참조를 null로 설정하면 기본 객체가 어떻게 해제되는지를 보여줍니다.

메모리 관리 Java

스택 메모리란 무엇인가요? Java?

스택 메모리 Java 스택은 각 스레드의 메서드 프레임, 지역 변수 및 참조 변수를 저장하는 JVM 메모리 영역입니다. 스택은 항상 후입선출(LIFO) 방식으로 접근되므로 가장 최근에 호출된 메서드가 맨 위에 있으며, 해당 메서드의 지역 변수는 메서드 프레임과 함께 푸시되고 팝됩니다.

각각의 실은 Java 가상 머신은 자체 스택을 가지며, 이 스택은 설계상 메서드 호출을 격리하고 스레드로부터 안전하게 보호합니다. int, boolean, double과 같은 기본형 지역 변수는 프레임 내부에 직접 저장되는 반면, 스택에 저장된 객체 참조는 힙에 할당된 객체를 가리킵니다.

힙 메모리란 무엇인가요? Java?

힙 메모리는 모든 데이터를 저장하는 JVM의 공유 영역입니다. Java `new` 연산자로 생성된 객체와 배열, 그리고 해당 객체에 속하는 참조 변수들을 인스턴스 필드로 함께 저장합니다. 스택과 달리 힙은 모든 스레드에서 공유되므로 객체 접근 시 동기화가 필요한 경우가 많습니다.

힙은 가비지 컬렉터가 관리하는 영역입니다. 최신 HotSpot JVM은 힙을 수명이 짧은 객체를 위한 Young Generation과 수명이 긴 객체를 위한 Old Generation으로 나누고, 클래스 메타데이터는 Metaspace라는 별도의 네이티브 영역에 저장합니다.

메모리 할당 Java

메모리 할당 Java 힙(Heap)은 JVM이 프로그램 실행 중에 변수, 클래스 및 구조체의 인스턴스를 위해 가상 메모리 영역을 할당하는 과정입니다. 객체 선언 시에는 메모리가 할당되지 않고 참조만 생성됩니다. 실제 객체 할당은 `new` 연산자를 통해 이루어지므로 모든 객체는 힙에 저장됩니다.

The Java 메모리 할당은 다음과 같은 부분으로 나뉩니다.

  1. 더미
  2. 스택
  3. Code
  4. 정적인

이러한 메모리 분할은 런타임을 효율적으로 관리하는 데 필요합니다.

  • The Code 해당 섹션에는 컴파일된 내용이 포함되어 있습니다. 바이트 코드.
  • The 스택 섹션 스토어 메서드, 지역 변수 및 참조 변수.
  • The 더미 섹션에 다음이 포함되어 있습니다. 사물 또한 인스턴스 필드로 저장된 참조 변수를 포함할 수도 있습니다.
  • The 정적인 섹션 보유 정적 데이터 및 정적 메서드 모든 인스턴스에서 공유됩니다.

로컬 변수와 인스턴스 변수의 차이점

JVM에서 각 변수 유형이 어디에 위치하는지 이해하면 스택과 힙의 동작 방식을 이해하는 데 도움이 됩니다. 인스턴스 변수 선언 클래스 내부이지만 메서드 외부에 있습니다.그리고 그것은 객체의 일부로서 힙에 존재합니다.

class Student{ 
int num; // num is instance variable 
public void showData{}

A 지역 변수 선언 메서드 내부, 메서드 인자 포함그리고 활성 프레임 내부의 스택에 존재합니다.

public void sum(int a){

int x = a + 3;

// a, x are local variables

}

스택과 힙의 차이점

스택과 힙은 JVM 내부에서 서로 다른 문제를 해결합니다. 스택은 각 스레드에 메서드 범위와 관련된 수명이 짧은 데이터를 위한 빠르고 결정적인 할당을 제공하는 반면, 힙은 모든 스레드가 참조할 수 있는 수명이 긴 객체를 위한 공유 영역을 제공합니다. 아래 짧은 영상은 이어지는 설명에 앞서 스택과 힙의 차이점을 간략하게 요약합니다.

여기에서 확인하세요 비디오에 접근할 수 없는 경우

스택과 힙이 어떻게 상호 작용하는지 알아보려면, 메서드 m1을 호출하는 main 메서드를 생각해 보세요.

public void m1{
int x = 20;
}

JVM 스택에서 메서드 m1에 대한 프레임이 생성됩니다.

Java 스택과 힙

아래 이미지에서 볼 수 있듯이, m1의 변수 x는 스택의 m1 프레임에도 생성됩니다.

Java 스택과 힙

메서드 m1은 메서드 m2를 호출합니다. 스택에는 m1에 대한 프레임 위에 m2에 대한 새로운 프레임이 생성됩니다.

Java 스택과 힙

Java 스택과 힙

로컬 변수 b와 c는 스택의 m2 프레임 내부에도 생성됩니다.

public void m2(int b){
boolean c;
}

다음으로, m2는 m3 메서드를 호출합니다. 마찬가지로, 아래 그림과 같이 m3에 대한 프레임이 스택의 맨 위에 생성됩니다.

Java 스택과 힙

Java 스택과 힙

이제 메서드 m3이 Account 클래스의 객체를 생성한다고 가정해 보겠습니다. Account 클래스는 두 개의 속성을 가지고 있습니다. 인스턴스 변수 int p와 int q.

class Account {
    int p;
    int q;
}

다음은 m3 메서드의 코드입니다.

public void m3(){
    Account ref = new Account();
    // more code
}

`new Account()` 문은 힙에 Account 객체를 생성합니다.

Java 스택과 힙

참조 변수 ref는 m3 프레임 내부의 스택에 생성됩니다.

Java 스택과 힙

할당 연산자는 참조 변수가 힙에 있는 객체를 가리키도록 합니다.

Java 스택과 힙

메서드 실행이 완료되면 제어권은 호출한 메서드, 즉 이 경우 m2 메서드로 돌아갑니다.

Java 스택과 힙

메서드 m3의 프레임이 스택에서 제거되었습니다.

Java 스택과 힙

참조 변수가 더 이상 힙의 객체를 가리키지 않으므로 해당 객체는 가비지 컬렉션 대상이 됩니다.

Java 스택과 힙

m2 메서드가 완료되면 스택에서 제거되고 해당 메서드의 모든 변수는 더 이상 사용할 수 없게 됩니다. m1 메서드도 마찬가지이며, 최종적으로 제어는 메인 메서드로 돌아갑니다.

객체가 인스턴스 변수로 다른 객체에 대한 참조를 가지고 있다면 어떻게 될까요?

public static void main(String args[]) {
    A parent = new A();
    // more code
}
class A {
    B child = new B();
    int e;
}
class B {
    int c;
    int d;
}

이 경우 참조 변수 child는 A 객체의 일부로 힙에 존재하며, 아래와 같이 자체 B 객체를 가리킵니다.

Java 스택과 힙

가비지 컬렉션이란? Java?

쓰레기 수거 Java 가비지 컬렉터는 JVM이 메모리 관리를 자동으로 수행하는 프로세스입니다. 가비지 컬렉터는 더 이상 유효한 참조에서 접근할 수 없는 객체를 찾아 해당 객체의 메모리를 회수합니다. 동적 메모리 할당은 `new` 연산자를 통해 이루어지며, 프로그램에서 해당 객체에 대한 참조를 더 이상 보유하지 않을 때까지 메모리가 할당된 상태로 유지됩니다.

참조가 더 이상 남아 있지 않으면 해당 객체는 더 이상 필요하지 않은 것으로 간주되어 객체가 차지하는 메모리를 회수할 수 있습니다. 객체를 명시적으로 파괴할 필요는 없습니다. Java 가비지 컬렉터를 통해 메모리 할당 해제를 자동으로 처리합니다.

이 기술의 근간을 이루는 것은 다음과 같이 알려져 있습니다. 쓰레기 수거메모리를 제대로 해제하지 못하는 프로그램은 결국 할당할 메모리가 하나도 남지 않으면 충돌합니다. 이러한 프로그램을 메모리 해제 실패 프로그램이라고 합니다. 메모리 누수. 쓰레기 수거 Java 자동으로 실행됩니다 프로그램 수명 주기 전반에 걸쳐 적용되므로 수동 할당 해제의 부담이 없어지고 메모리 누수 위험이 줄어듭니다.

반면 C 언어에서는 프로그래머가 free() 함수를 통해 동적으로 할당된 메모리를 해제해야 합니다. 바로 이 부분이 그 예입니다. Java 메모리 관리 측면에서 상당한 이점이 있습니다.

최신 HotSpot JVM에는 다양한 워크로드에 맞춰 최적화된 여러 가비지 컬렉터가 포함되어 있습니다. 기본 G1 가비지 컬렉터는 수 기가바이트 규모의 힙에서 처리량과 일시 정지 시간의 균형을 맞추는 것을 목표로 합니다. ZGC와 Shenandoah는 매우 큰 힙에서 1밀리초 미만의 일시 정지 시간을 목표로 하므로 처리량이 매우 높습니다.trac지연 시간에 민감한 서비스에 적합합니다. 적절한 컬렉터를 선택하고 Young Generation, Old Generation 및 Metaspace 크기를 조정하는 것은 핵심 기술입니다. Java 공연 예술.

참고 : 모든 객체는 메모리의 힙 영역에 생성되며, 이 영역은 가비지 컬렉터가 관리하는 영역입니다.

예: 가비지 수집기 메커니즘을 배우려면 Java

이 가이드에서는 간단한 프로그램 내에서 참조가 가비지 컬렉션 대상이 되는 시점을 보여줍니다.

단계 1) 다음 코드를 편집기에 복사하세요.

class Student{
int a;
int b;
  public void setData(int c,int d){
    a=c;
    b=d;
  }
  public void showData(){
    System.out.println("Value of a = "+a);
    System.out.println("Value of b = "+b);
  }
  public static void main(String args[]){
    Student s1 = new Student();
    Student s2 = new Student();
    s1.setData(1,2);
    s2.setData(3,4);
    s1.showData();
    s2.showData();
    //Student s3;
    //s3=s2;
    //s3.showData();
    //s2=null;
    //s3.showData();
    //s3=null;
    //s3.showData();
  }
}

단계 2) 코드를 저장, 컴파일 및 실행합니다. 그림에서 보는 것처럼 두 개의 객체와 두 개의 참조 변수가 생성됩니다.

 가비지 수집기 메커니즘

단계 3) 20번, 21번, 22번 줄의 주석을 해제하세요. 코드를 저장하고 컴파일한 후 실행하세요.

단계 4) 아래 그림에서 볼 수 있듯이, 이제 두 개의 참조 변수가 동일한 객체를 가리킵니다.

가비지 수집기 메커니즘

단계 5) 23번과 24번 줄의 주석을 해제하세요. 코드를 저장하고 컴파일한 후 실행하세요.

단계 6) 아래 그림과 같이 s2는 null이 되지만 s3는 여전히 객체를 가리키고 있으므로 해당 객체는 아직 가비지 컬렉션 대상이 아닙니다.

 가비지 수집기 메커니즘

단계 7) 25번과 26번 줄의 주석을 해제하세요. 코드를 저장하고 컴파일한 후 실행하세요.

단계 8) 이 시점에서는 해당 객체를 가리키는 참조가 없으므로 가비지 컬렉션 대상이 됩니다. 가비지 컬렉터는 해당 객체를 메모리에서 제거하며, 이후에는 해당 객체를 다시 가져올 방법이 없습니다.

 가비지 컬렉터 배우기

객체를 삭제하는 방법 Java?

Java 수동 삭제 연산자를 제공하지 않으므로, 표준적인 방법은 가비지 컬렉터가 해당 객체를 회수할 수 있도록 객체에 대한 모든 참조를 제거하는 것입니다.

1) 객체가 가비지 컬렉션 대상이 되도록 하려면 해당 객체를 가리키는 모든 참조 변수를 null로 할당해야 합니다.

2) 기본 데이터 유형은 객체가 아니므로 null을 할당할 수 없습니다. 주변 스택 프레임이 제거될 때 해당 저장 공간이 자동으로 회수됩니다.

개체를 삭제하는 방법 Java

자주 묻는 질문

스택은 메서드 프레임, 지역 변수 및 참조를 스레드별로 후입선출(LIFO) 방식으로 저장합니다. 힙은 `new`로 생성된 모든 객체를 저장하며 스레드 간에 공유되므로 가비지 컬렉터가 관리합니다.

가비지 컬렉터는 활성 스레드 및 정적 필드와 같은 GC 루트에서 시작하여 참조 체인을 따라 이동합니다. 루트에서 접근할 수 없는 객체는 접근할 수 없는 객체로 간주되어 다음 컬렉션 주기 동안 회수 대상이 됩니다.

Young Generation은 Eden 및 Survivor 공간에 수명이 짧은 객체를 저장합니다. Old Generation은 여러 컬렉션 후에도 유지되는 객체를 저장합니다. Metaspace는 클래스 메타데이터를 저장하는 네이티브 메모리 영역으로, 기존의 PermGen을 대체합니다. Java 8.

G1은 기본 GC이며 수 기가바이트 힙에서 실행되는 대부분의 워크로드에 적합합니다. ZGC와 Shenandoah는 매우 큰 힙에서 밀리초 미만의 지연 시간을 목표로 하며, 지연 시간에 민감한 서비스에 적합한 선택입니다. Java 17 이상

객체를 가리키는 모든 참조를 null로 설정하거나, 스택 프레임이 팝될 때 참조가 스코프에서 벗어나도록 합니다. 객체에 도달하는 활성 참조가 더 이상 없으면 가비지 컬렉터가 힙 메모리를 회수합니다.

예. AI 기반 튜닝 도구는 GC 로그, 할당률 및 일시 중지 히스토그램을 분석하여 힙 크기, 컬렉터 플래그 및 Young Generation 비율을 권장합니다. 특히 G1, ZGC 및 Shenandoah 워크로드에서 수동 튜닝에 비해 피드백 주기를 단축합니다.

AI 기반 관찰 플랫폼은 힙 덤프와 실시간 메트릭을 수집한 후, 보존된 객체 그래프를 클러스터링하여 의심스러운 클래스와 참조 체인을 표시합니다. 이를 통해 수동 힙 분석보다 빠르게 메모리 누수 후보를 찾아내고, 팀이 프로덕션 환경에서 근본 원인을 파악하는 데 도움을 줍니다.

이 게시물을 요약하면 다음과 같습니다.