KKanging

JVM 가비지 컬렉터(GC) 기초 본문

JAVA/JVM

JVM 가비지 컬렉터(GC) 기초

천방지축 개발자 2024. 8. 25. 19:00

GC이란


C/C++ 같은 OS 의존도 높은 Native 언어와 Java 언어의 차이

C/C++ 같이 프로그램 한 언어가 직접 OS가 실행하는 언어들은 Memory Leak 문제를 많이 겪는다.

 

Memory Leak 란?

 

“동적으로 할당한 메모리가 free(할당 해제)될 수 없는 상태가 된 것.” 이다.

 

즉, C/C++ 같은 Native 언어들은 heap을 할당하고 해제하는 해동을 오로지 개발자들의 코드로 이루어진다.

 

따라서 이러한 heap 메모리 관리를 잘못하여 동적으로 할당한 메모리가 더이상 free 할 수 없어서 사용하지도 않는 데이터

가 메모리를 차지하여 성능 저하 및 심하면 프로그램 강제 종료가 되는 상황을 말한다.

 

Java 언어에서는 메모리 해제한 적 없는데?

 

위 문제를 보고 이런 생각이 들 것이다.

“Java 프로그램 짜면서 메모리 해제를 한적이 있었나?”

 

당연하다 Java 는 기본적으로 실행하는 방법이 OS가 직접 실행하는 네이티브 언어들과 달리 JVM 위에서 실행한다.

 

즉, 다른 네이티브 언어들과 달리 OS와 프로그램 사이에 JVM이라는 실행 단위가 더 추가 된것이다.

 

JVM 이 그래서 뭐가 중요한데?

 

Java 의 JVM은 그냥 실행자 역할로 이해해서는 안된다.

 

JVM은 Java 프로그램 실행에 필요한 모든 것을 관리한다.

처음 프로그램이 시작되면

메모리를 OS로 부터 할당받고,

자바 바이트 코드를 동적으로 로딩하여 다양한 기능을 지원하고,

바이트 코드로 인터프리팅 및 최적화된 컴파일을 진행한다.

또한 실행 단위에서 메모리를 관리한다.

 

JVM ? GC ?

 

여기서 주목 해야하는 기능은 메모리 관리이다.

Java 개발자가 메모리 해제에 신경 안쓸 수 있게 Garbage Collection (일명 GC) 기능을 지원한다.

GC 는 Heap 메모리에서 안쓰이는 메모리를 개발자가 일일히 관리를 안해줘도 자동으로 회수해주는 기능이다.

GC는 만능인가?

 

이렇게만 보면 이런 생각이 들지도 모른다.

“와 C/C++ 개발자들은 노가다하는거 우리는 신경안쓰고 개발해도 되겠네?”

 

물론 반은 맞는 말이다. Java 개발자들은 일일히 메모리 해제를 신경 안쓰고도 누수가 안될 것이고 해제 된 메모리에 접근을 하는 일 또한 없다.

 

하지만 은탄환은 없다는 말과 같이 무조건 장점만 있는것이 아니다.

장점

  • 메모리 누수 X
  • 해제 메모리 접근 X
  • 해제한 메모리 중복 해제 X

단점

  • GC 작업 또한 순수 오버헤드
  • GC 메모리 해제 시점을 개발자는 알 지 못함
  • 메모리 누수로 완전한 해방이 아님

GC 작업 또한 하나의 프로그램 작업이기 때문에 프로그램 실행 중 GC 작업은 동시성 문제 또는 프로그램의 저하를 야기할 수 있다.

그리고 메모리 누수를 완벽히 해결하는 것이 아니라서 개발자들은 GC가 해준다고 해당 작동원리나 장애 대응 방법을 알지 못한다면 큰 문제가 생길 때 대처하지 못할 것이다.

(오히려 Java 개발자들은 OS 만 알면 되는 C/C++ 개발자 보다 JVM이라는 알아야 하는 단위가 더 생긴 것이다.)

 

GC 프로세스


 

GC 알고리즘

GC 의 대표적인 알고리즘 2개

  • Reference Counting
  • Mark And Sweep

Reference Counting

Reference Counting 은 기본적인 GC 알고리즘이다

Root Space 에는 다음이 있다고 생각하면 된다.

  1. Stack 의 로컬 변수
  2. Method 의 static 변수
  3. Native Method Stack 의 JNI 참조

Root Space 가 참조하는 객체와 객체가 참조하는 객체 식으로 꼬리를 물면서 객체 참조가 이뤄질 것이다.

Reference Counting은 이러한 구조에서 객체가 참죄되는 Reference 수를 세어 0이 되면 메모리에서 해제하는 알고리즘이다.

 

Reference Counting 의 단점 : 순환 참조 문제

위 처럼 순환 참조 식의 객체 참조는 Root Space로 부터 끊어진다 해도 서로 참조하고 있기 때문에 참조 수가 0이 될 수 없다 따라서 메모리 누수를 야기할 수 있다.

 

Mark And Sweep 알고리즘

Mark And Sweep 알고리즘은 순회를 돌아서 root space 와 연결되지 않은 메모리를 탐색한다.

연결된 객체 = Reachable Objects

연결되지 않은 객체 (garbage 대상) = Unreachable Objects

라고 부른다.

Mark And Sweep 은 다음 3가지 과정이 있는데

Mark : rechable 객체를 Marking 한다.

Sweep : making 되지 않은 객체를 Heap 에서 제거한다.

Compaction : 메모리를 정리한 후 존재하는 메모리를 효율적이게 시작주소로 모아주는 작업

Compaction은 가비지 컬렉터 종류에 따라 해당 과정이 없는 경우도 있다.

 

Heap의 메모리 구조


Heap 의 메모리 구조는 Yong generation 과 Old Generation 으로 구분된다.

Yong Generation 은 Eden , Survival 0 survival 1 3개로 구분된다.

Heap 메모리를 GC가 청소하는 방법

Heap 메모리를 위처럼 나눈 이유

 

GC 작업 또한 하나의 비용이다.

GC가 작업할 때 마다 모든 메모리를 탐색하고 정리 대상으로 둔다면 작업 비용이 더 커질 것이다.

따라서 오래 쓰이는 객체와 짧게 쓰이다 삭제될 객체를 구분짓고 정리 대상으로 본다.

 

그리고 JVM 설계자는 대부분의 객체는 금방 생성되고 사라지는 객체라 본다. 위 이미지는 이 주장을 뒷받침하는 근거이다.

 

GC가 메모리를 어떻게 활용할까?

 

>객체 생성

처음 객체가 만들어지면 위처럼 Eden 영역에 생성 된다.

 

>Minor GC

계속 객체가 생성 되어서 Eden 영역이 가득 차면 minor GC가 실행한다.

minor GC는 위 GC 프로세스 대로 메모리를 정리하고 계속 쓰이는 객체는 Survival 영역에 적재한다.

Survival 영역에 적재할때 또는 GC 작업을 할 때 다음과 같은 작업을 한다.

  • Survival 0,1 둘 중 한 곳에만 채울 수 있다 (둘 중 한 곳은 비워둬야한다)
  • 한번의 GC 작업을 하면 각 객체 마다 age 값을 카운팅한다.

>Major GC

계속 age 가 쌓이면 특정 JVM이 지정한 특정 age 가 커지면 Old generation 영역으로 이동한다.

이 과정을 Promotion 이라 한다.

 

Old generation 이 꽉 차면 Major GC 가 정리하는데 이는 오랜 시간이 걸리는 작업이고 stop-the-world 가 발생한다.

'JAVA > JVM' 카테고리의 다른 글

JVM 클래스 로딩 과정  (0) 2024.08.13
JVM 메모리 구조  (0) 2024.08.13
JVM 이란?  (0) 2024.08.13