지난 번에 JVM 메모리 구조와 역할에 대해서 알아봤습니다.
그렇지만 클래스, 메서드, 객체, 변수 등의 메모리 할당/해제를 모두 개발자가 관리해줄 순 없다. 이를 개발자가 매 코드마다 메모리 관련 메서드로 명시적인 관리를 하지 않아도 되게 해주는 것이 '가비지 컬렉터(Garbage Collector)'의 역할 중 하나이다.
웹 애플리케이션을 만들 때 검증된 라이브러리나 프레임워크를 이용하는 게 더 안전하고 편리한 것처럼, 메모리 관리도 개발자가 직접 하기보다는 JVM에 맡기는 것이다.
프로그램 실행 시 JVM 옵션을 주어서 OS에 요청한 사이즈만큼의 메모리를 할당받아서 실행하게 된다.
할당받은 것 이상으로 메모리를 사용하게 되면 에러가 나면서 프로그램이 종료된다.
그러므로 현재 프로세스에서 메모리 누수가 발생해도 현재 실행 중인 것만 종료되고 다른 것에는 영향을 주지 않는다.
이렇게 자바는 가상 머신을 사용함으로써 OS 레벨에서의 메모리 누수(Memory Leak)는 불가능하게 된다는 장점이 있다.
메모리의
힙(Heap)영역에 할당된 부분이 참조되지 않는데도 해제되지 않은 채로 메모리를 계속 점유하고 있는 것
https://www.fatalerrors.org/a/java-memory-leak.html
우선 가비지 컬렉터가 수행하는 가비지 컬렉션에 대해 알아보자.
가비지 컬렉션(Garbage Collection, GC)은 메모리 관리 기법 중의 하나로, 프로그램이 동적으로 할당했던 메모리 영역 중에서 필요 없게 된 영역을 해제하는 기능이다. 1959년 무렵 리스프의 문제를 해결하기 위해 존 매카시가 개발하였다.
- 위키백과 -
💡 가비지 컬렉터는 내부적으로 finalize() 메서드를 호출하여 객체를 메모리에서 해제시킨다.
가비지 컬렉션은 자바만의 기능은 아니다. 개발자가 힙을 사용할 수 있는 만큼 자유롭게 사용하고, 더 이상 사용되지 않는 객체들은 가비지 컬렉션을 담당하는 프로세스가 자동으로 메모리에서 제거하도록 하는 것이 가비지 컬렉션의 기본 개념이다. 때문에 위에서 설명한 메모리 누수에 해당되는 인스턴스들이 가비지 컬렉션 대상이 되는 것이다.
그런데 어떻게 자동으로 메모리에서 제거하도록 하는 것일까?
가비지 컬렉터가 어떻게 메모리 상황을 다 알고 가비지를 어떻게 판단하며 가비지를 어떻게 수집하는지 들여다보자.
가비지 컬렉터는 힙 영역에 있는 객체를 사용되는(Reachable) 것과 사용되지 않는(Unreachable)의 상태로 구분한다.
💡 오라클 공식 문서에서는 객체의 참조 유형을 구분짓고 그 정도를 'Reachability'로 표현하고 있다.
힙에 있는 객체들에 대한 참조는 다음 4가지 종류 중 하나인데,
이들 중 힙 내의 다른 객체에 의한 참조를 제외한 나머지 3개가 Root set(시작점 세트)로 Reachability를 판가름하는 기준이 된다. Root Set으로부터 어떤 식으로든 참조 관계가 있다면 Reachable Object, 없다면 Unreachable Object라 판단한다. 간단히는 객체들 간의 참조 사슬 시작점이라 보면 된다.