포스트

JVM 시리즈 - 자바 메모리 영역

자바 메모리 영역

런타임 데이터 영역

자바 런타임 데이터 영역은 총 5개로 메서드 영역, 가상 머신 스택, 네이티브 메서드 스택, 힙, PC 레지스터로 구성되어 있다.

프로그램 카운터

현재 실행 중인 스레드의 ‘바이트 코드 줄 번호 표시기’이다. 바이트코드 인터프리터는 카운터의 값을 바꿔 다음에 실행할 바이트코드 명령어를 선택한다. 자바 가상 머신에서의 멀티스레딩은 CPU 코어를 교대로 사용하기에, 각 스레드에는 고유한 프로그램 카운터가 필요하다. 따라서 이는 쓰레드간 격리되어 있고, 스레드 프라이빗 메모리인 것이다.

자바 가상 머신 스택

일반적으로 스택 영역이라고 불린다. 여기도 스레드 프라이빗하다. 스레드와 운명을 같이 한다.(생성,삭제 시기가 일치한다)
스택 영역에는 지역 변수 테이블이 있는데, 여기에는 다양한 기본 데이터 타입, 객체 참조, 반환 주소 타입을 저장한다. 슬롯 하나는 32 비트기에, double 타입은 슬롯 2개를 차지한다. 이 공간은 컴파일 과정에서 할당된다. 스택 프레임에서 지역 변수용 공간의 크기는 정해져있다. 이 ‘크기’는 슬롯의 개수이다.
자바 가상 머신 명세는 스택 메모리 영역에서 2가지 오류가 발생할 수 있도록 정의했다. 첫 번째는, 스레드가 요청한 스택 깊이가 가상 머신이 허용하는 깊이보다 크다면 StackOverflowError 를 던진다. 둘째, 스택 용량을 동적으로 확장할 수 있는 자바 가상 머신에서는 스택을 확장할 떄, 여유 메모리가 충분하지 않다면 OutOfMemoryError 를 던진다.

네이티브 메서드 스택

가상 머신 스택과 비슷한 역할을 한다. 네이티브 메서드 스택은 네이티브 메서드를 실행할 때 사용한다. 이 영역을 가상 머신 구현자에 따라서 가상 머신 스택과 합쳐놓기도 한다.

자바 힙

자바 애플리케이션이 사용할 수 있는 가장 큰 메모리다. 모든 스레드가 공유하며, 가상 머신이 구동될 때 만들어진다. ‘거의’ 모든 객체 인스턴스를 저장한다. 명세상으로는 모든 객체 인스턴스와 배열은 힙에 할당되지만, ‘거의’ 라고 말한 이유는 앞으로 자바 언어가 발전하면서 최적화 방식에 따라서 달라질 수 있는 여지가 있기 때문이다.
GC 가 발생하는 공간으로, 신세대, 구세대, 영구 세대, 에덴, 생존자 공간 등으로 나뉜다고 표현되는 문헌도 있지만 이는 가비지 컬렉터의 특성에 따른 설계 방식일 뿐, 명세상 이렇게 나눠진다는 이야기는 없다. 이는 주류 가상 머신으로 사용되는 핫스팟 가상 머신에서 채택한 G1 컬렉터에 따른 동작 방법일 뿐이다.
메모리 할당 관점에서 힙은 모든 스레드가 공유한다. 명세에 따르면 힙은 물리적으로 떨어진 메모리에 위치해도 상관없으나 논리적으로는 연속되어야 한다. 마치 파일을 저장할 떄의 디스크 공간과 같다. 그러나, 대다수 가상 머신이 큰 객체는 물리적으로도 연속된 메모리 공간을 사용하도록 구현하며, 이는 저장 효율이 좋고 구현 로직이 단순하기 때문이다.
자바 힙의 크기를 고정하거나, 확장 가능하게 할 수 있다(-Xmx, -Xms 매개 변수 사용). 새로운 인스턴스에 할당해 줄 힙 공간이 부족하면 OOM Error 를 던진다.

메서드 영역

자바 힙처럼 모든 스레드가 공유한다. 가상 머신이 읽어 들인 타입 정보, 상수, 정적 변수, JIT 컴파일러가 컴파일한 코드 캐시 등을 저장하는데 이용된다. 핫스팟 가상 머신 개발 팀이 가비지 컬렉터의 수집 범위를 메서드 영역까지 확장하기로 결정했기에, 메서드 영역을 영구 세대에 구현했다. 따라서 영구 세대와 메서드 영역이 혼동되고는 하지만 명세에 나와 있는 내용은 아니다.
메서드 영역을 영구 세대에 구현한 설계 때문에 자바 애플리케이션이 메모리 오버플로우를 겪을 가능성이 커졌다. 영구 세대의 최대 크기는 –XX:MaxPermSize로 제한되며, 이 값을 설정하지 않더라도 기본값은 정해져 있다. 그러나, J9 과 JRockit 과 같은 가상 머신은 프로세스가 쓸 수 있는 메모리 최댓값에 손을 대지 않았다.
명세 상, 메서드 영역에 제약을 거의 두지 않았다. 심지어 가비지 컬렉션을 하지 않아도 괜찮다. 메서드 영역에서 회수할 대상은 대부분 상수 풀과 타입이기에 회수 효과가 매우 작다.

런타임 상수 풀

런타임 상수 풀은 메서드 영역의 일부다. 클래스 버전, 필드, 메서드, 인터페이스 등 클래스 파일에 포함된 설명 정보에 더해 컴파일타임에 생성된 다양한 리터럴과 심벌 참조가 저장된다.

다이렉트 메모리

다이렉트 메모리는 가상 머신 런타임에 속하지 않고, 자바 가상 머신 명세에서도 정의되지 않았다. 하지만 자주 쓰이는 메모리이며 OOM error 의 원인이 될 수도 있다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.