[면접스터디] 자바 5주차 - JVM과 GC (1~8)

동춘·2024년 11월 25일

[면접스터디] 자바

목록 보기
13/15
post-thumbnail

1. JVM의 구조에 대해서 설명해 주세요.

JVM(Java Virtual Machine)은 Java 애플리케이션 실행을 위해 설계된 가상 머신으로, 클래스 로더 시스템, 메모리 영역, 실행 엔진으로 구성됩니다.
메모리 영역은 Method Area, Heap, Stack, Program Counter, Native Method Stack으로 나뉘며, 애플리케이션 데이터를 효율적으로 관리합니다.
실행 엔진은 바이트코드를 해석하거나 JIT 컴파일로 네이티브 코드로 변환하여 프로그램을 실행합니다.

  1. 클래스 로더 시스템 (Class Loader Subsystem)
  • Java 바이트코드(.class 파일)를 로드하여 JVM 메모리에 배치합니다.
  • 로드 → 링크 → 초기화 단계를 통해 클래스 관리합니다.
    • 로드(Loading): .class 파일을 메모리에 로드.
    • 링크(Linking): 클래스 간의 참조 관계를 해결.
    • 초기화(Initialization): 클래스 초기화 블록(static)과 정적 변수를 설정.
  1. 메모리 영역 (Runtime Data Area)
  • JVM이 Java 프로그램 실행을 위해 메모리를 관리하는 영역입니다.
    • Method Area: 클래스 정보, 메서드 코드, 상수 풀
    • Heap: 객체 및 배열이 저장.
    • Stack: 스레드별로 생성되며, 메서드 호출 시 지역 변수와 매개변수 저장.
    • Program Counter: 현재 실행 중인 명령어의 주소 저장.
    • Native Method Stack: JNI를 통해 호출된 네이티브 메서드 관련 데이터 저장.
  1. 실행 엔진(Execution Engine)
  • JVM의 핵심 컴포넌트로, 바이트코드를 실제 머신 코드로 변환하고 실행.

  • 주요 구성 요소

    • 인터프리터: 바이트코드를 한 줄씩 해석하여 실행.

    • JIT 컴파일러(Just-In-Time Compiler): 인터프리터가 반복 또는 빈번하게 사용되는 코드를 감지하면, 해당 부분을 JIT 컴파일러에게 넘깁니다. JIT 컴파일러는 이를 네이티브 코드로 변환하고, 변환된 코드를 메서드 영역의 Code Cache 영역에 저장합니다. 그 후 동일한 코드가 호출될 때, 인터프리터가 컴파일된 네이티브 코드를 호출하여 실행합니다. 네이티브 코드는 컴퓨터가 직접 실행항 수 있는 이진 형태의 코드로, 하드웨어에 최적화되어 있어 인터프리터보다 훨씬 빠르게 실행됩니다.

    • Garbage Collector: 메모리 관리.

  1. 자바 네이티브 인터페이스(Java Native Interface)
  • 네이티브 라이브러리를 추상화한 인터페이스
  • JNI를 통해 Java와 네이티브 라이브러리(C/C++) 간 상호작용 지원.

2. 클래스 로더에 대해 설명해 주세요.

클래스 로더(Class Loader)는 JVM에서 클래스(.class 파일)를 메모리에 로드하고, 실행 준비를 하는 역할을 합니다.
주요 과정은 로딩(Loading), 링크(Linking), 초기화(Initialization)로 구성되며, 클래스의 메타데이터와 정적 변수를 Method Area에 저장합니다.
대표적으로 Bootstrap ClassLoader, Extension ClassLoader, Application ClassLoader가 있으며, 상위 클래스로더부터 순차적으로 클래스를 탐색합니다.

  • 클래스 로더의 종류
    • Bootstrap ClassLoader
      • 가장 최상위 클래스 로더
      • JVM이 시작될 때 Java 표준 라이브러리(java.lang, java.util)를 로드.
    • Extension ClassLoader
      • 확장 라이브러리(JAVA_HOME/lib/ext)를 로드.
    • Application ClassLoader
      • 애플리케이션 클래스 경로(CLASSPATH)에서 사용자 정의 클래스를 로드.
  • 클래스 로딩 과정
    1. 로딩 (Loading): .class 파일을 메모리에 읽음.
    2. 링크 (Linking)
      • 검증 (Verification): 클래스 파일 형식 검증.
      • 준비 (Preparation): 정적 변수 및 기본 값 설정.
      • 해결 (Resolution): 클래스의 상수 풀 참조를 실제 메모리로 매핑.
    3. 초기화 (Initialization): 정적 블록과 정적 변수 초기화.
  • 동작 순서
    • 클래스 요청:
      • 특정 클래스가 필요한 경우, 애플리케이션에서 해당 클래스 이름으로 클래스 로더에게 요청을 보냅니다.
    • 부모 클래스 로더로 위임:
      • 현재 클래스 로더는 먼저 부모 클래스 로더에게 해당 클래스를 로드할 수 있는지 요청합니다.
        • 예를 들어, Application ClassLoader는 먼저 Extension ClassLoader에게 요청하고, Extension ClassLoader는 Bootstrap ClassLoader에게 요청합니다.
    • 클래스 로드 시도:
      • 부모 클래스 로더가 클래스를 로드하지 못하면, 현재 클래스 로더가 클래스를 로드하려고 시도합니다.
    • 클래스 로드 성공 여부:
      • 클래스를 성공적으로 로드하면, JVM에 로드된 클래스가 반환됩니다.
      • 로드하지 못하면 ClassNotFoundException 예외가 발생합니다.

3. JVM 메모리 구조를 자세히 설명해 주세요.

JVM(Java Virtual Machine)의 메모리 영역은 Method Area, Heap, Stack, Program Counter, Native Method Stack으로 나뉩니다.

  1. 메서드 영역 (Method Area)
  • 클래스 메타데이터(필드, 메서드, 상수 풀) 저장.
  • 모든 스레드가 공유.
  • Java 8부터는 Metaspace로 관리되며, 메모리 제한은 OS에 의해 결정.
  1. 힙 (Heap)
  • 객체 및 배열 저장.
  • 모든 스레드가 공유.
  • 가비지 컬렉터(GC)에 의해 관리.
  • Young Generation, Old Generation으로 나뉘어 관리.
  1. 스택 (Stack)
  • 각 스레드별로 독립적으로 생성.
  • 메서드 호출 시 생성되는 스택 프레임에 지역 변수와 매개변수 저장.
  • LIFO(Last In First Out) 방식.
  1. 프로그램 카운터 (PC Register)
  • 현재 실행 중인 명령어의 주소(바이트코드 명령어의 모음)를 저장.
  • 각 스레드마다 독립적으로 존재.
  1. 네이티브 메서드 스택 (Native Method Stack)
  • JNI를 통해 호출된 네이티브 코드(C/C++) 관련 데이터를 저장.

4. GC(Garbage Collection)란 무엇인가요?

GC(Garbage Collection)는 JVM에서 사용되지 않는 객체를 자동으로 정리하여 메모리를 회수하는 메커니즘입니다.
참조되지 않는 객체를 탐지하여 제거하여 메모리 누수 방지와 효율적인 메모리 관리를 돕습니다.
Java는 GC를 통해 개발자가 직접 메모리를 해제할 필요 없이 안정적인 메모리 관리를 제공합니다.

  • 작동 원리: GC는 참조되지 않는 객체를 탐지하여 메모리에서 제거.
  • 알고리즘:
    • Mark and Sweep: 객체의 참조 여부를 확인(Mark)한 후, 참조되지 않은 객체를 제거(Sweep).
    • Generational GC:
      • Young Generation: 새로 생성된 객체 관리.
      • Old Generation: 오래된 객체 관리.
  • 유형: Serial GC, Parallel GC, CMS GC, G1 GC, ZGC 등.

5. GC의 장단점을 설명해 주세요.

장점으로는 GC는 메모리를 자동으로 관리하여 메모리 누수를 방지하고, 개발자가 메모리 해제를 신경 쓰지 않아도 되어 코드 작성이 간결합니다.
단점은 GC 실행 중 Stop-the-World로 애플리케이션이 일시 중단될 수 있으며, 실행 시점이 예측 불가능해 성능에 영향을 줄 가능성이 있습니다.
GC 튜닝이 필요한 경우 설정이 복잡할 수 있어, 애플리케이션에 맞는 최적화가 필요합니다.

  • 장점
    • 자동으로 메모리를 관리해줍니다.
    • 사용하지 않는 객체를 제거, 메모리 누수를 방지합니다.
    • GC는 JVM으로 관리되어 메모리 관리 방식이 플랫폼에 독립적입니다.
  • 단점
    • 성능 오버헤드 발생
      • GC는 CPU 리소스를 소비하여 성능저하를 일으킵니다.
      • 특히 Stop-the-World상황이 발생할 수 있습니다.
    • 실행 시점 예측이 불가합니다.
      • JVM이 GC 실행 시점을 결정하므로 예상치 못한 시점에 GC가 실행되면 지연이 발생합니다.
    • 복잡한 튜닝 필요: GC의 성능을 최적화하려면 설정 및 분석 필요합니다.

6. (좀더 다뤄보기) GC를 모니터링해야 하는 이유

GC를 모니터링하면 GC 실행 빈도와 시간을 확인하여 성능 저하의 원인을 파악할 수 있습니다.
메모리 누수나 객체 과다 생성으로 인한 OutOfMemoryError를 사전에 발견하고 해결할 수 있습니다.
GC 튜닝 및 JVM 설정 최적화를 통해 애플리케이션 성능과 안정성을 유지할 수 있습니다.

7. (좀더 다뤄보기) 자바로 jvm 응용 프로그램을 개발한 후에 운영하다보면 out of memory가 나올 수 있는데 이 에러가 발생했을때 어떻게 대처할 것 같으세요?

OutOfMemoryError가 발생하면 먼저 GC 로그와 힙 덤프를 분석하여 메모리 누수나 객체 과다 생성을 확인합니다.
JVM 메모리 설정(예: -Xmx 및 -XX:MaxMetaspaceSize)을 조정하거나, 불필요한 객체 참조를 제거하고 코드 최적화를 수행합니다.
GC 알고리즘이나 힙 메모리 구조를 재설정하여 크기를 조정합니다. 메모리 관리와 GC 성능을 개선합니다.

  • 문제 해결 및 튜닝
    • High Pause Time: G1 GC, ZGC 사용.
    • Frequent GC: 힙 크기 조정, 객체 수명 최적화.

8. (좀더 다뤄보기) 메모리 누수를 어떻게 확인할 것인가요?

메모리 누수는 GC 로그와 힙 덤프를 분석하여, 참조가 끊어지지 않은 객체가 메모리에 남아 있는지 확인합니다.
Eclipse MAT, VisualVM 등 분석 도구를 사용해 누수를 유발하는 객체나 정적 필드 등을 식별합니다.
코드 리뷰를 통해 static 변수, 이벤트 리스너, 컬렉션 등이 메모리를 계속 점유하는 문제를 찾아 해결합니다.

  • 메모리누수는 GC가 동작하지 않아 생기는 문제입니다
  • 그렇다고 GC가 너무 많이 일어나면 cpu의 리소스의 오버헤드를 일으켜 성능저하를 일으킵니다.
  • 최적화가 매우 중요하다.
profile
건강하개

0개의 댓글