[5주차] JVM과 GC

Dev.Dana·2024년 11월 26일

Java

목록 보기
5/7
post-thumbnail

1. JVM이란?

1. JVM의 정의와 역할

  • JVM(Java Virtual Machine)은 자바 프로그램이 실행되는 가상의 컴퓨터이다.
  • 자바 코드를 이해할 수 있도록 바이트코드를 읽고 실제 실행하는 역할을 한다.
  • 자바 애플리케이션을 실행하고 메모리 관리, 가비지 컬렉션, 운영체제와의 상호작용을 담당한다.

2. JVM의 구조

1. 클래스 로더(Class Loader):

  • 자바 프로그램에 필요한 클래스를 읽고 메모리에 로드한다.

2. 메모리 영역(Memory Area):

  • JVM이 실행되는 동안 데이터를 저장하고 관리하는 공간.
  • 5가지 영역 : Method 영역, Heap, Stack, PC 레지스터, Native Method Stack

3. 실행 엔진(Execution Engine):

  • 바이트코드를 실제로 실행하는 부분.
  • 인터프리터와 JIT(Just-In-Time) 컴파일러, GC가 포함된다.
    JIT : 성능을 높이기 위해 많이 사용되는 코드를 컴파일해 빠르게 실행하는 엔진.

3. JVM의 메모리 구조

내가그린 jvm메모리구조

1. Method 영역

메서드 영역은 가상머신이 읽어 들인 타입 정보, 상수, 정적 변수, JIT컴파일러가 컴파일한 코드 캐시등을 저장하는데 이용된다.
메서드 영역은 모든 스레드가 공유하는 영역이다.

메서드 영역안에는 런타임 상수 풀도 포함이 되며, 런타임 상수 풀은 클래스 로딩 시 생성되는 데이터 구조다. 클래스 파일의 상수 정보 (문자열 리터럴, 숫자 상수, 심볼릭 참조 등)를 저장한다. 이 정보는 클래스 파일의 상수 풀 테이블에서 가져오고, 런타임에도 새로운 상수가 추가될 수 있다.

String Pool과는 무슨관계?
String Pool은 힙 영역에 있으며 문자열 리터럴을 저장하는 역할을 한다.

2. 자바 힙 (Heap 영역)

자바 힙은 자바 애플리케이션이 사용할 수 있는 가장 큰 메모리이다. 몯느 스레드가 공유하며 가상머신이 구동될 때 만들어진다.
이 메모리영역의 목적은 객체 인스턴스를 저장하는 것이고, 자바 세계의 '거의' 모든 객체 인스턴스가 이 영역에 할당된다.
자바 힙은 GC가 관리하는 메모리 영역이기 때문에 어느 문헌에서는 GC힙으로 불릴때도 있다.
모든 스레드가 공유하는 영역이다. 따라서 객체 할당 효율을 높이고자 스레드 로컬 할당 버퍼 여러개로 나뉜다.

  • 새로운 인스턴스에 할당해 줄 힙 공간이 부족하고, 힙을 더 할당할 수 없다면 OutOfMemoryError

3. 자바 가상 머신 스택 (Stack영역)

각 메서드가 호출될 때마다 JVM은 스택 프레임을 만들어 지역 변수 테이블, 피연산자 스택, 메서드 반환값 등의 정보를 저장한다.
지역 변수 테이블에는 JVM이 컴파일타임에 알 수 있는 기본 데이터 타입, 객체 참조, 반환 주소 타입을 저장한다.

  • 스레드가 요청한 스택의 깊이가 가상 머신이 허용하는 깊이보다 크다면 StackOverFlowError
  • 스택을 확장하려는 시점에 여유 메모리가 충분하지 않다면 OutOfMemoryError

자바의 메모리 영역을 힙/스택으로 구분하는 사람이 많은데 이는 전통적인 C/C++프로그램의 메모리 구조에서 기인한다. 자바의 메모리 영역은 훨씬 더 복잡하다. 스택이라고 하면 보통 자바가상머신 스택을 얘기하는데 그중 특히 '지역 변수 테이블'을 가리킬 때가 많다.

4. PC 레지스터

프로그램 타운터 레지스터는 작은 메모리 영역이다. 현재 실행중인 스레드의 바이트코드 명령어의 주소가 기록되는 곳.
JVM에서의 멀티스레딩은 CPU 코어를 여러 스레드가 교대로 사용하는 방식으로 구현되기 때문에 스레드가 전환되면서 이전에 실행하다 멈춘 지점을 정확하게 복원하려면 스레드 각각에 고유한 프로그램 카운터가 필요하다.
-> 각 스레드의 카운터는 서로 영향을 주지 않는 독립된 영역에 저장된다. (= 스레드 프라이빗 메모리)

5. Native Method Stack

가상 머신 스택과 매우 비슷한 역할을 한다. 하지만 다른점은 *네이티브 메서드를 실행할 때 사용한다는 것

네이티브 메서드란 ?
자바가 아닌 C, C++ 등의 네이티브 언어로 작성된 메서드.
자바 코드에서 직접 실행할 수 없는 기능(하드웨어 제어, 운영체제와의 상호작용 등)을 수행하기 위해 사용된다.

네이티브 메서드 스택에서도 스택 허용 깊이를 초과하면 StackOverFlowError, 스택 확장에 실패하면 OutOfMemoryError를 던질 수 있다.


4. GC(Garbage Collection)란?

프로그램 카운터, 가상머신 스택, 네이티브 메서드 스택같은 경우에는 스레드 프라이빗하다. 스레드에 종속되어 있는 메모리 영역이기 때문에 스레드와 함께 생성되고 소멸한다. 따라서 이 영역의 메모리 할당과 회수는 고민하지 않아도 된다.
반면 자바 힙과 메서드 영역은 불확실한게 아주 많다. 프로그램이 어떤 객체를 생성할지, 얼마나 많이 만들지는 오직 런타임에만 알 수 있는 것이다. 이 메모리 영역들의 할당과 회수는 동적으로 이뤄진다. 가비지 컬렉터가 바로 이 영역을 관리하는 역할을 한다.

1. GC의 정의

GC는 JVM이 더 이상 사용하지 않는 객체를 찾아 메모리에서 제거하는 자동 메모리 관리 시스템. 프로그래머가 직접 메모리를 해제하지 않고, 가비지 컬렉터가 죽은 객체를 알아서 메모리에서 해제시켜주기 때문에 메모리 누수와 관리 부담을 줄일 수 있다.

2. GC 알고리즘 종류

1. 마크-스윕 (Mark-Sweep)

  • 객체를 마킹한 후, 마킹되지 않은 객체를 회수.

마크 스윕 알고리즘의 단점은 실행 효율이 일정하지 않고, 메모리 파편화가 심하다는 것이다.

2. 마크-카피 (Mark-Copy)

회수할 객체가 많아질수록 효율이 떨어지기 때문에 새로 등장한 카피 알고리즘은
가용 메모리를 똑같은 크기의 두 블럭으로 나눠 한 번에 한 블록만 사용하는 알고리즘이다.

  • 살아있는 객체를 다른 영역으로 복사하고 기존 영역을 정리.
  • 주로 Young GC에서 자주쓰인다.

3. 마크-컴팩트 (Mark-Compact)

마크카피 알고리즘은 객체 생존율이 높을수록 복사할게 많아져 효율이 떨어진다. 공간을 50%도 더 낭비하게 될 수 없기에 Old GC에는 적합하지 않다. 그래서 나온것이 마크 컴팩트 알고리즘이다.

  • 마킹 후, 살아남은 객체를 한쪽으로 모아 메모리 단편화 해결.
  • 주로 Old GC에서 자주쓰인다.

표시 단계는 마크-스윕과 같지만 다음 컴팩트 단계에서 생존한 모든 객체를 메모리 영역의 한쪽 끝으로 모은 다음 나머지 공간을 한꺼번에 비운다.


5. GC 모니터링 및 문제 해결

1. GC를 모니터링해야 하는 이유

2. OutOfMemoryError 대응 방법

profile
어제의 나보단 나은 오늘의 내가 되기를

0개의 댓글