3장#2 - 가비지 컬렉터와 메모리 할당 전략
3.6 저지연 가비지 컬렉터
3.7 적합한 가비지 컬렉터 선택하기
3.8 실전 : 메모리 할당과 회수 전략
자바 기술 시스템이 제공하는 자동 메모리 관리의 가장 근본적인 목표는 객체의 메모리를 '자동으로 할당' 하고 객체에 할당된 메모리를 '자동으로 회수' 하는 것이다.
객체 할당 규칙은 고정된 게 아니다. "자바 가상 머신 명세" 는 객체 생성과 저장 방식을 상세하게 명시하지 않는다. 그 대신 현재 사용하는 GC 와 메모리 관련 가상 머신 매개 변수 설정값에 따라 달라질 수 있도록 했다.
아래 예시는 시리얼 컬렉터를 예시로 든다. 해당 예시를 이해하면, 다른 컬렉터들의 메모리 할당 규칙을 이해하는데 무리가 없을 것이다.
3.8.1 객체는 먼저 에덴에 할당된다.
대부분의 경우 객체는 신세대 에덴에 할당된다. 에덴에 공간이 부족해지면 가상 머신은 마이너 GC 를 시작한다.
마이너 GC 시 살아남은 객체들은 생존자 공간에 할당되고, 해당 과정을 반복하다가 오래 살아남은 객체들을 대상으로 구세대에 할당한다.
3.8.2 큰 객체는 곧바로 구세대에 할당된다.
큰 객체란 커다란 '연속된' 메모리 공간을 필요로 하는 자바 객체를 말한다. 매우 긴 문자열이나, 원소가 매우 많은 배열이 대표적인 예다.
메모리를 할당해야 하는 가상 머신에게 큰 객체의 등장은 타협 불가능한 나쁜 소식이다. 왜냐면 여유공간이 많이 있음에도 GC 를 해야만 하는 상황을 자주 만들기 때문이다.
'연속된' 메모리를 공간을 확보하기 위해서 수 많은 객체를 다른 곳으로 옮겨야 하므로 심각한 메모리 복사 오버헤드를 동반한다.
이럴 때 -XX:PretenureSizeThreshold 매개 변수를 설정하면 설정값보다 큰 객체를 곧바로 구세대에 할당한다.
3.8.3 나이가 차면 구세대로 옮겨진다.
핫스팟 VM 의 컬렉터 대부분은 힙 메모리에 관리에 세대 단위 컬렉션을 활용한다. 그래서 메모리를 청소할 때 어떤 생존 객체를 신세대에 남겨 두고 어떤 생존 객체를 구세대로 옮길지 정해야 한다. 이를 위해 가상 머신은 각 객체의 객체 해더에 세대 나이 카운터를 두도록 했다.
객체는 주로 에덴에서 태어난다. 태어났을 때의 나이는 0이다. 첫 번째 마이너 GC 에서 살아남은 객체는, 생존자 공간이 충분하면 생존자 공간으로 옮겨지면서 나이가 1 증가한다. 그리고 생존자 공간에서 마이너 GC 를 한 번 겪을 때마다 다시 1씩 증가한다.
구세대로 승격되는 나이는 -XX:MaxTenuringThreshold 매개 변수로 정한다. 기본값은 GC 종류와 JDK 버전마다 다를 수 있다.
3.8.4 공간이 비좁으면 강제로 승격시킨다.
다양한 프로그램의 메모리 사용 패턴에 더 정밀하게 대응하기 위해 핫스팟 가상 머신은 나이가 -XX:MaxTenuringThreshold 보다 적어도 구세대로 승격시키기도 한다.
바로 '생존자 공간 점유율' 이 바로 그 조건이다. 기본값은 50% 이라서 생존 객체 전체의 크기 총합이 생존자 공간의 절반을 넘어서면 모든 객체를 구세대로 옮긴다.
Last updated