1 분 소요

최근에 JDK 11 -> 21 버전업하면서 Old Gen 사용량이 감소한걸 확인했었는데 이유가 궁금해서 최적화 기법이 들어간게 있는지 찾아보다가 Class Data Sharing이 있다는걸 알게됐다. 실제로 이 기능이 영향을 줬는지 공식 문서 기준으로 근거는 찾지 못했지만 이 기능이 무슨 역할을 하는지 알면 좋을 것 같아서 간단히 정리했다.

Class Data Sharing(CDS)

말 그대로 클래스 데이터를 공유하는 방식을 말한다.
다만 애플리케이션 클래스 전부를 공유하는게 아니고 일반적으로 JDK 표준 클래스를 대상으로 한다.

  • java.lang.*
  • java.util.*
  • 기타 등등
  • (참고) 애플리케이션 클래스도 포함하려면 AppCDS를 활성화 해야한다 (JEP 310)

이렇게 대상이 되는 클래스들을 classes.jsa에 넣어두고 시작 시점에 별도 작업없이 classes.jsa를 참조해서 사용하므로 CDS 사용 시 애플리케이션 서버 시작 시간이 감소한다는 장점이 있다.

비활성화하려면 -Xshare:off를 추가하면 된다.

classes.jsa는 JDK 설치 디렉터리에 있다고 한다.

  • Linux/MacOS: /lib/[arch]/server/classes.jsa
  • Windows: /bin/server/classes.jsa

그 별도 작업이 뭔데 CDS보다 느리게 동작하는지?

CDS를 사용하지 않는다면 JDK 표준 클래스들은 .class -> Klass변환하고 metaspace 영역에 등록해야한다.
변환 과정에서 오버헤드가 발생하는데 CDS는 jsa에 있는 Klass를 직접 참조한다. 그래서 CDS를 쓰면 시작 시간이 감소한다.

JDK 11에서 CDS는 잘 적용되는가

JDK 11은 -Xshare:dump를 명시하지 않으면 jsa 파일이 있을 때만 사용하고 그렇지 않으면 넘어간다.
그래서 CDS 효과를 보려면 -Xshare:dump를 명시해야 한다. 나같은 경우 명시를 안해서 CDS 효과가 없었을걸로 추측된다.

  • -Xshare:dump: archive(jsa 파일)를 생성하라는 옵션

JEP 341에서는 JDK 11에서 -Xshare:dump를 명시하지 않아 CDS 효과를 못보는 유저들이 많아서 JDK 12+부터는 명시하지 않아도 기본적으로 사용할 수 있도록 했다고 설명하고 있다.

Archived Heap

metaspace에 등록되는 Klass는 Java 표준 라이브러리를 쓰려면 mirror 객체가 필요하다.
mirror 객체는 Heap에서 관리되는 java.lang.Class 객체다. CDS는 이걸 Archived Heap에 관리한다.
(Klass가 런타임에서 표현되는 인스턴스를 말하고 Java 표준 라이브러리는 getClass()같은 리플렉션 API를 말한다)

(내 생각) Old Gen 사용량은 왜 감소했을까?

JDK-8196991에서는 archive space가 논리적으로는 Old Gen에 속해있지만 실제로 GC에 의해 수집되지 않는다고 한다.
Old Gen은 오랫동안 수집되지 않았지만 수집이 될 수 있는 영역이므로 archive space와 Old Gen을 분리해야 한다는 코멘트가 있지만 정말로 그렇게 분리가 되었는지 공식문서 기준으로는 찾지 못했다..🥲

만약 분리가 된게 맞다면 Old Gen 사용량이 감소한게 이해가 된다. 참고로 총 Heap 사용량은 거의 변하지 않았다.
archive space이 Old Gen 수집 대상에서 제외돼서 감소한 것처럼 보이지만 총 Heap 사용량은 차이가 없어서 그렇다고 생각했다.

References

카테고리:

업데이트: