JVM & GC 추가 정리

웃음인·2025년 4월 10일

Java

목록 보기
35/37
post-thumbnail

JVM의 역할

1. 바이트코드(.class 파일) 실행

   - 자바 코드는 .java 파일에서 작성됨

   - 컴파일러(javac)가 이를 바이트코드(.class)로 변환

   - JVM이 바이트코드를 실행하여 프로그램 동작

2. 플랫폼 독립성 제공

   - 한 번 작성하면 어디서든 실행 가능 (Write Once, Run Anywhere)

   - 운영체제(OS)와 관계없이 바이트코드를 실행할 수 있도록 환경을 제공

3. 메모리 관리 (Garbage Collection)

   - 객체를 자동으로 관리하고, 필요 없는 객체를 삭제하여 메모리를 정리함


JVM 실행 과정 (Java 코드 실행 흐름)

  1. Java 코드 작성 (.java 파일)
  2. 컴파일 (javac) → 바이트코드 (.class 파일) 생성
  3. JVM 실행 → 클래스 로더가 .class 파일 로드
  4. 실행 엔진이 바이트코드를 해석하고 실행
  5. 필요할 경우 JIT 컴파일러가 최적화
  6. 객체 사용이 끝나면 GC가 메모리 정리
  7. 프로그램 종료

JVM 구조 중 클래스 로더

클래스 로더의 종류

   1. 부트스트랩 클래스 로더 (Bootstrap ClassLoader)

  • JVM 최상위 클래스 로더 (C/C++로 구현됨)
  • rt.jar 같은 Java의 핵심 클래스 (java.lang, java.util)를 로드
  • 사용자가 직접 제어할 수 없음
System.out.println(String.class.getClassLoader());  // 출력: null (Bootstrap ClassLoader)

👉 String.class는 부트스트랩 클래스 로더가 로드했기 때문에 null 반환

   2. 확장 클래스 로더 (Extension ClassLoader)

  • lib/ext 디렉터리에 있는 확장 클래스(javax.crypto, javax.sound 등)를 로드
  • sun.misc.Launcher$ExtClassLoader로 구현됨
System.out.println(com.sun.crypto.provider.AESKeyGenerator.class.getClassLoader());
// 출력: sun.misc.Launcher$ExtClassLoader@xxxxxx

👉 AESKeyGenerator는 확장 클래스 로더가 로드했기 때문에 출력

   3. 애플리케이션 클래스 로더 (Application ClassLoader)

  • 사용자가 작성한 클래스 (classpath 경로에 있는 클래스)를 로드
  • java -cp 또는 CLASSPATH 환경 변수에서 지정한 클래스 로드
  • sun.misc.Launcher$AppClassLoader로 구현됨
System.out.println(ClassLoaderExample.class.getClassLoader());
// 출력: sun.misc.Launcher$AppClassLoader@xxxxxx

👉 우리가 만든 클래스는 애플리케이션 클래스 로더가 로드

클래스 로딩 과정 (3단계)

로딩 (Loading), 링크 (Linking), 초기화 (Initialization) 3단계를 거쳐 이루어진다.

로딩 (Loading) 예제

class A {
    static int value = 10;
    static { 
        System.out.println("클래스 A 로딩됨"); 
    }
}

public class Test {
    public static void main(String[] args) {
        A obj;  // 여기서는 아직 클래스 로딩 X
        obj = new A();  // 여기서 클래스 로딩됨!
    }
}
// 출력: 클래스 A 로딩됨

👉 obj = new A(); 실행될 때 클래스 로딩 발생!

초기화 (Initialization) 예제

class B {
    static int num = 100;
    static {
        System.out.println("클래스 B 초기화됨");
    }
}

public class Test {
    public static void main(String[] args) {
        System.out.println(B.num);  // 클래스 B가 여기서 초기화됨!
    }
}
// 출력: 클래스 B 초기화됨
//       100

👉 B.num을 호출하는 순간 클래스가 초기화됨!

JVM 구조

JVM 메모리는 메서드(Method) 영역, 힙(Heap) 영역, 스택(Stack) 영역,
PC 레지스터(PC Register), 네이티브 메서드 스택(Native Stack)
으로 총 5가지 주요 영역으로 나뉘어 있다.

메서드(Method) 영역 예제

class Example {
    static int staticVar = 100;  // 메서드 영역에 저장됨
}

  ✔ staticVar 변수는 메서드 영역(Method Area)에 저장됨!
  ✔ 모든 인스턴스가 공유하는 영역


힙(Heap) 영역 예제

class Person {
    String name;  // 힙 영역에 저장됨
}

public class Test {
    public static void main(String[] args) {
        Person p1 = new Person();  // 힙에 저장됨
        Person p2 = new Person();  // 또 다른 객체 생성됨
    }
}

  ✔ p1, p2는 힙 영역에 각각 저장됨

스택(Stack) 영역 예제

public class Test {
    public static void main(String[] args) {
        int x = 10;  // 스택 영역에 저장됨
        add(x);      // add() 메서드 호출 → 새로운 스택 프레임 생성
    }

    public static void add(int num) {
        int result = num + 5;  // 스택 영역에 저장됨
    }
}

x, num, result → 스택 영역에 저장됨
add()가 실행되면 새로운 스택 프레임(Stack Frame) 생성
add() 실행이 끝나면 스택 프레임 제거됨


GC(Garbage Collection)의 장단점

GC 장점

  1. 메모리 자동 관리 (수동 해제 불필요)
Person p = new Person();  // GC가 알아서 정리!
p = null;  // 더 이상 참조되지 않으면 GC 대상이 됨
    }
}

   ✔ 개발자가 직접 메모리를 해제할 필요가 없음!

  1. 메모리 누수(Leak) 방지
void noMemoryLeak() {
    Integer num = new Integer(10);  // GC가 필요할 때 자동 해제!
}

   ✔ Java에서는 GC가 자동으로 불필요한 객체를 정리해서 메모리 누수 걱정 없음!

  1. Dangling Pointer(잘못된 메모리 참조) 문제 방지
Integer num = new Integer(5);
num = null;  // GC가 자동 정리 → Dangling Pointer 문제 없음!

   ✔ Dangling Pointer 문제 방지 → 안정적인 코드 작성 가능!

  1. JVM이 OS에 독립적으로 메모리 관리

  2. GC 최적화를 통한 성능 개선 (최신 GC 알고리즘 지원)

  • G1 GC, ZGC, Shenandoah GC 등 최신 GC는 성능 최적화 가능

    • G1 GC(Garbage First GC)
      -  대용량 힙 메모리를 가진 애플리케이션에 최적화
      -  중단 시간을 최소화하여 서버 성능 향상

    • ZGC (JDK 11~)
      -  초저지연(10ms 이하) GC
      -  대규모 시스템에서도 빠르게 동작

0개의 댓글