본문 바로가기
Java

[Java] Method Area, PermGen 그리고 Metaspace

by soro.k 2022. 10. 6.

 

 

들어가기 전에

static 예약어는 전역적으로 사용하기 위한 변수나 메소드, 객체에 사용한다. Method Area에 저장되어서 JVM의 생성과 소멸에 맞춰서 라이프 사이클이 정해져있다고 다들 알고 있을 것이다. 나도 그렇게 알고 있었는데 검색을 하다 보니 처음 듣는 PermGen, Metaspace 같은 용어들이 나왔다. 알면 알수록 명확해지지 않고 헷갈리는 부분이 많았어서 나를 위해서도 그리고 나같이 잘 모르고 있던 분들을 위해 정리를 해보려고 한다. 

 

 

JVM memory structure

출처 : https://www.programmersought.com/article/4905216600/

 

위의 그림은 우리가 흔히 볼 수 있는 JVM의 메모리 구조이다. 여기서 Heap과 Method Area는 있지만 PermGen과 MetaSpace는 보이지 않는다. 도대체 PermGen과 MetaSpace는 어디서 나온 걸까?

 

 

Heap Memory

우선 Heap Memory의 구조에 대해 살펴보겠다. Heap 영역은 모든 스레드가 공유하는 메모리가 저장되는 영역으로 클래스 인스턴스와 Arrays가 저장된다. 가장 큰 특징으로는 GC에 의해서 데이터가 관리된다는 점이다. 여기서 드디어 PermGen 영역을 확인할 수 있다. 

 

출처 : https://www.programmersought.com/article/4905216600/

 

 

Non-Heap Memory 

PermGen은 Permanent Generation의 약어이고 이름에서 알 수 있듯이 JVM이 시작되고 끝이 날 때까지 영구적으로 보존하는 데이터가 담기는 영역이다. 그러면 PermGen은 Heap 영역 안에 있는 것일까?

 

 

출처 : https://javapapers.com/core-java/java-jvm-memory-types/
출처 : https://docs.oracle.com/javase/7/docs/technotes/guides/management/jconsole.html

Oracle의 공식 문서와 그림을 같이 보면 Permanent Generation은 Heap 메모리가 아닌 Non-Heap 메모리에 포함되어 있음을 알 수 있다. 스택오버플로우 질문 페이지에서 더 자세한 내용을 확인할 수 있다. 이 내용과 관련해서 여러 문서들을 보다 보면 PermGen 영역은 논리적으로는 Heap 메모리 안에 있다는 표현을 볼 수 있는데 항상 메인 메모리(Heap)과 분리되는 특별한 영역이라고 명시되어있으니 이해를 쉽게 하기 위해서는 Non-Heap 메모리에 있다고만 알고 있어도 되지 않을까 하는 개인적인 생각이다.

 

Method Area vs PermGen

그렇다면 Method Area와 PermGen은 무슨 차이가 있는 걸까?

 

Method area에는 런타임 상수 풀(runtime constant pool), 필드 및 메소드 데이터 등 관련 메타 데이터 정보들이 저장된다고 알고 있는데 PermGen의 설명을 봐도 비슷하게 데이터를 저장하고 있는 것을 알 수 있다.

 

첫 번째로 스택오버플로우에 두 개의 영역이 같은 거라고 이해해도 되겠느냐는 질문이 있다. 답변의 대부분의 의견은 Method area는 Permanent Generation의 일부라는 것이다.

출처 : https://stackoverflow.com/questions/9095748/method-area-and-permgen

 

두 번째로 Naver D2에 게시된 게시글 중 NHN 개발자분이 쓰신 GC에 대한 양질의 글이었는데 Permanent Generation 영역은 Method Area라고 작성하셨다. 다른 블로그 글에서도 단순히 Permanent Generation은 JVM 벤더마다 이름이 다를 뿐 Method Area랑 똑같은 개념이라는 설명을 보기도 했다. 

출처 : https://d2.naver.com/helloworld/1329

 

 

나의 개인적인 결론으로는 이 두 개의 구분을 크게 의미있게 생각하지 않아도 되겠다라는 것이다. 부분 집합이거나 그 자체여도 개념을 이해하는 데는 문제가 없을 것이다. PermGen을 Method Area라고 생각하고 PermGen에 대해 더 자세히 알아보기로 하자.

벤더 사에 따라 Method Area를 칭하는 용어가 다른 것이라서 Oracle에서는 그 영역이 PermGen이라고 생각하면 된다.

 

 

Permanent Generation

 

출처 : https://www.javatpoint.com/permgen-space-java
출처 : https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html

 

Permanent generation 영역은 Method Area와 같이 로드된 클래스 메타데이터와 static으로 선언된 필드, 메소드 그리고 객체까지 모두 저장되는 공간이다. 아래의 oracle docs에서 자바 7 이전에는 String pool도 포함되어있었지만 이후부터는 Heap 메모리의 주요 부분이 Youn/Old Generation 영역에 저장된다는 걸 알 수 있다.

출처 : https://docs.oracle.com/javase/8/docs/technotes/guides/vm/enhancements-7.html

 

PermGen의 기본 메모리 크기는 32bit JVM에서는 64MB, 64bit에서는 82MB이고 JVM Option으로 기본 크기를 수동으로 변경할 수 있지만 이 포스팅에서는 다루지 않는다. 변경하는 방법은 이 포스팅을 통해 알 수 있다. 하지만 아무리 기본 크기를 수동으로 변경할 수 있다고 하더라도 공간의 최댓값이 정해져있기 때문에 OufOfMemoryError가 발생한다는 문제점이 있었다. 

 

 

Mataspace

이제 PermGen은 어느정도 이해가 됐으니 Metaspace로 넘어가보겠다.

자바 8에 들어서면서 PermGen이 사라지고 새로 만들어진 영역이 Metaspace이다. Metaspace는 PermGen이 위치해 있었던 Heap과 연속적으로 위치한 Non-heap Memory가 아닌 Native Memory에 할당되어 OutOfMemoryError가 발생하지 않는다.

출처 : https://www.programmersought.com/article/4905216600/

Non-heap Memory와 Native Memory의 차이점은 뭘까? 나머지 영역은 OS가 JVM에 할당한 메모리 크기만을 사용할 수 있지만 Native Memory는 OS의 메모리를 그대로 사용하기 때문에 메모리 제한이 없다. 하지만 크기 제한을 걸지 않았을 때 평균적인 클래스 생성을 넘어서서 방대한 양의 클래스를 로드하게 되면 서버 자체가 다운될 수 있다. 그래서 JVM의 옵션인 MaxMetaspace를 사용해서 크기 제한을 걸면 된다. 이렇게 Metaspacer가 생기면서 GC는 일종의 트리거를 얻게 됐는데 클래스 메타데이터 사용량이 최대로 지정한 Metaspace 크기에 도달하면 GC가 시행된다고 한다.

 

 

그런데 OutOfMemoryError도 문제이긴 했지만 Metaspace가 생겨난 이유는 정확한 뭘까?

출처 : https://openjdk.org/jeps/122

JVM의 종류 중 하나인 JRockit에는 PermGen 영역이 존재하지 않기 때문에 JRockit과 Hotspot을 통일감을 만들어주기 위해서이다. 오래된 기사이지만 왜 뜬금없이 JRockit이 나오지 이해가 안 간다면 이 아티클을 읽어보기를 추천한다.

 

 

위의 캡쳐본은 Permanent Generation를 제거한다는 제안서인데 문서를 더 읽다 보면 Metaspace에서는 클래스의 메타데이터가 Native Memory 안에 저장되고 interned Strings(상수 풀)과 static으로 선언된 정보들은 Heap Memory에 저장된다는 것을 알 수 있다.

출처 : https://openjdk.org/jeps/122

사실 이전과 다를 거 없이 static 객체는 참조하는 변수가 없으면 GC에 의해서 사라지고 그외의 static 변수들은 모두 JVM이 종료될 때 소멸된다고 생각하면 되겠다. 

 

 

 

 

참고

- Permgen vs Metaspace in Java - Baeldung

JEP 122: Remove the Permanent Generation

Where are static methods and static variables stored in Java?

- [Java] static이란?

- PermGen space Java

- One important change in Memory Management in Java 8