전체 글

Java 27 정식 출시, JDK 27 G1 기본 GC 통일과 컴팩트 객체 헤더 — 9개 JEP 변경점

xXfacebook페이스북

JDK 27이 2026년 9월 15일 정식 출시(GA)됐습니다. 발표 메일은 "Build 35 is therefore now the GA build, ready for production use."라고 밝히는데, 이 빌드는 2026년 8월 20일 두 번째 릴리스 후보로 내보내진 뒤 P1 버그 보고가 한 건도 없었던 상태입니다. JEP 9건이 실렸습니다.

9개 가운데 실행 환경의 기본값을 바꾸는 것은 두 개입니다 — 명령행에서 가비지 컬렉터를 지정하지 않은 환경의 기본 선택이 G1으로 통일되고(JEP 523), 컴팩트 객체 헤더가 기본 레이아웃이 됩니다(JEP 534). 아무 설정도 건드린 적 없는 배포일수록 기본값이 통째로 바뀌는 쪽에 해당합니다. 발표 메일과 JEP 원문, Oracle 로드맵을 겹쳐 읽은 정리이고 JDK 27을 직접 실행해 확인한 내용은 아닙니다. 단서는 2026년 9월 16일자 긱뉴스 토픽입니다.

JDK 27 정식 출시 — GA 빌드 35, JEP 9건

프로덕션용 빌드는 jdk.java.net/27에서 내려받을 수 있습니다. Linux/AArch64·Linux/x64, macOS/AArch64, Windows/x64 네 플랫폼용 바이너리와 sha256이 제공되고 라이선스는 Classpath Exception이 붙은 GNU GPL 2판입니다. 다만 이 페이지 본문에는 빌드 번호가 문장으로 적혀 있지 않습니다 — 빌드 35의 1차 출처는 발표 메일이고 다운로드 URL 경로의 /35/가 부합합니다.

JEP 내용 단계
JEP 523 G1을 모든 환경의 기본 컬렉터로 정식 — 기본값 변경
JEP 534 컴팩트 객체 헤더를 기본 레이아웃으로 정식 — 기본값 변경
JEP 527 TLS 1.3 양자내성 하이브리드 키 교환 정식 — X25519MLKEM768이 기본 최우선
JEP 536 JFR 인프로세스 데이터 비식별화 정식 — 기본 켜짐
JEP 531 Lazy Constants 프리뷰 3차
JEP 532 패턴·instanceof·switch의 기본형 타입 프리뷰 5차
JEP 533 Structured Concurrency 프리뷰 7차
JEP 538 암호화 객체의 PEM 인코딩 프리뷰 3차
JEP 537 Vector API 인큐베이터 12차

LTS 여부는 발표 메일에 언급이 없습니다. 답은 Oracle Java SE Support Roadmap에 있습니다 — 로드맵 표는 27을 non-LTS로 분류하고 8·11·17·21·25를 LTS로 적으며 다음 LTS는 2027년 9월의 Java 29입니다. 27의 프리미어 지원은 2027년 3월까지로 표기돼 있지만 이 날짜는 상용 Oracle JDK 기준이고 표 각주에는 LTS/non-LTS 구분과 날짜가 변경될 수 있다고 명시돼 있습니다. 릴리스 주기와 다음 버전 일정도 메일이 아니라 로드맵의 근거를 따릅니다.

기본 GC가 G1으로 통일됩니다 (JEP 523)

지금까지의 기본 선택은 JDK 9(JEP 248)에서 정해졌습니다. JVM은 프로세서가 둘 이상이고 물리 메모리가 1792MB 이상인 머신을 서버 클래스로 보아 G1을 골랐고 그 밖의 환경에서는 Serial이 기본이었습니다(Oracle JDK 26 가비지 컬렉션 튜닝 가이드의 Ergonomics 절). JEP 523이 든 유래는 JDK 9 당시 테스트입니다 — 단일 CPU 또는 1792MB 미만의 제약적 환경에서는 Serial이 처리량과 메모리 사용 면에서 뚜렷한 이점이 있었다는 것입니다.

JDK 27은 이 분기를 없앱니다. 명령행에서 컬렉터를 지정하지 않으면 프로세서 수와 가용 물리 메모리와 무관하게 항상 G1을 고릅니다.

JDK 9와 JDK 27의 기본 GC 선택 조건을 나란히 비교한 도식. JDK 9에서는 프로세서 2개 이상과 1792MB 이상 메모리를 갖춘 서버 클래스 머신에서만 G1을 골랐고, JDK 27에서는 명령행에서 지정하지 않으면 환경과 무관하게 항상 G1을 고른다.

명시적으로 고른 컬렉터가 있으면 그 설정이 항상 우선한다.

Serial은 사라지지 않았습니다. JEP은 기존 컬렉터의 폐지·제거를 목표가 아니라고 명시하고 제약적 환경의 일부 애플리케이션은 여전히 Serial이 가장 좋을 수 있으니 그런 경우 명시적으로 선택할 수 있다고 적습니다. 사용자가 명시적으로 고른 컬렉터는 JVM의 선택을 항상 이깁니다. 플래그는 -XX:+UseSerialGC이고 이 이름의 출처는 Oracle JDK 26 가비지 컬렉션 튜닝 가이드의 Available Collectors 절입니다 — 이 글을 쓰는 시점에 JDK 27용 Oracle 문서 URL은 아직 26 문서로 연결됩니다.

컴팩트 객체 헤더가 기본입니다 (JEP 534)

64비트 아키텍처에서 객체 헤더는 96비트에서 64비트로 줄어듭니다. JEP 534는 이 컴팩트 레이아웃을 HotSpot JVM의 기본 헤더 레이아웃으로 만들어 힙 크기를 줄이고 배포 밀도를 높이며 데이터 지역성을 개선합니다.

이번에 갑자기 들어온 기능이 아닙니다. JDK 24에서 JEP 450으로 실험 기능으로 들어왔고(이때는 -XX:+UnlockExperimentalVMOptions가 필요했고 "96~128비트에서 64비트로" 줄인다고 적습니다), JDK 25의 JEP 519가 정식 기능으로 올렸지만 기본값은 꺼져 있었습니다. JDK 27에서 기본이 켜집니다.

객체 헤더 비트 수가 96비트에서 64비트로 줄어드는 것과 JDK 24 실험 기능, JDK 25 정식 기능이지만 기본 꺼짐, JDK 27 기본 켜짐이라는 세 단계를 함께 보여주는 도식.

기본을 끄는 플래그는 마이너스를 붙인 UseCompactObjectHeaders다.

원문이 든 수치는 네 개입니다. 특정 설정에서 SPECjbb2015 벤치마크가 힙 공간을 22% 적게, CPU 시간을 8% 적게 썼습니다. 또 다른 설정에서는 같은 벤치마크의 GC 횟수가 G1과 Parallel 컬렉터 모두에서 15% 줄었습니다. 고도로 병렬화된 JSON 파서 벤치마크는 실행 시간이 10% 줄었습니다. 네 수치는 전부 특정 설정·특정 벤치마크에 한정된 결과라 원문의 한정 표현("In one setting", "In another setting")을 떼면 과장이 됩니다. Amazon은 수백 개 서비스를 프로덕션에서 이 기능으로 운영하며 그 대부분이 JDK 21과 JDK 17에 백포트한 버전이라고 합니다.

기본을 되돌리는 방법도 명시돼 있습니다. JDK 25에서 켜던 -XX:+UseCompactObjectHeaders는 기본이 되어 필요 없어지고 필요하면 -XX:-UseCompactObjectHeaders로 끕니다. 옛 96비트 레이아웃을 지금 제거하는 것은 목표가 아니지만 Motivation에는 이를 향후 릴리스에서 폐기(deprecate)할 의사가 적혀 있고 Project Valhalla를 위한 비트 네 개를 이미 예약해 뒀다는 말도 Risks and Assumptions에 있습니다. 옛 레이아웃 전제의 코드가 있다면 '지금은 남아 있으나 폐기가 예고됐다'까지가 원문이 말하는 범위입니다.

한 가지는 분명히 해 둡니다 — JEP 534 원문에는 네이티브 에이전트 같은 특정 도구를 향한 호환성 경고가 없습니다. 이 글도 원문에 없는 영향 시나리오를 덧붙이지 않았습니다.

보안 쪽 변경 — 양자내성 TLS 키 교환과 JFR 비식별화

TLS 1.3에 하이브리드 키 교환이 들어왔습니다(JEP 527). 양자내성 알고리즘과 전통 알고리즘을 조합해 미래의 양자컴퓨팅 공격에 대비하는 방식이고 JEP이 든 동기는 "지금 수집해서 나중에 복호화한다(harvest now, decrypt later)"는 위협입니다. 재료는 이미 있었습니다 — Java 21의 KEM API(JEP 452)와 Java 24의 ML-KEM(JEP 496)입니다.

추가된 하이브리드 그룹은 셋입니다 — X25519MLKEM768(X25519 ECDHE와 ML-KEM-768의 조합), SecP256r1MLKEM768(secp256r1 곡선과 ML-KEM-768), SecP384r1MLKEM1024(secp384r1 곡선과 ML-KEM-1024). 이름은 IANA 규격과 같습니다. 기본 최우선은 X25519MLKEM768 하나입니다. JDK의 TLS 1.3 구현은 기본 목록 맨 앞에 이 그룹을 놓고 TLS 1.3 클라이언트는 X25519MLKEM768과 x25519 두 키 셰어를 제공합니다. 나머지 두 하이브리드 그룹은 기본으로 활성화돼 있지 않습니다. 기본 목록은 이 하이브리드에 전통 그룹 여덟 개(x25519, secp256r1, secp384r1, secp521r1, x448, ffdhe2048, ffdhe3072, ffdhe4096)를 더한 아홉 개이고 조정은 시스템 속성 jdk.tls.namedGroups 또는 SSLParameters::setNamedGroups로 합니다.

JDK 27 TLS 1.3의 기본 named groups 아홉 개를 순서대로 보여주는 표. 맨 앞의 X25519MLKEM768이 기본 최우선이고, SecP256r1MLKEM768과 SecP384r1MLKEM1024는 기본 비활성으로 따로 표시돼 있다.

클라이언트가 제공하는 키 셰어는 X25519MLKEM768과 x25519 두 개다.

JFR도 바뀝니다(JEP 536). 프로세스를 떠나기 전에 명령행 인자와 환경변수·시스템 프로퍼티의 초기 값을 가립니다 — 키(이름)는 그대로 기록되고 필터에 맞은 값 자리만 [REDACTED]로 치환됩니다. 이 가림은 기본으로 켜집니다. redact-key 기본 필터는 *password*·*secret*·*token* 등 열세 패턴이고 redact-argument 기본 목록은 이와 비슷하되 author까지 맞지 않도록 *auth*가 빠져 있고 -*password * 같은 복수 인자 매칭이 포함됩니다.

필터는 -XX:FlightRecorderOptions의 하위 옵션 redact-argument·redact-key로 다룹니다. glob(*, ?)을 지원하고 세미콜론으로 구분하며 + 접두로 기본 필터에 더하고 @파일명으로 필터 파일을 읽습니다. 예전 동작으로 되돌리려면 redact-argument=none,redact-key=none, 동작 확인은 -Xlog:jfr+redact=debug입니다. 암호화 객체의 PEM 인코딩(JEP 538)도 보안 쪽 변경이지만 정식 기능이 아니라 세 번째 프리뷰라서 다음 절에서 함께 정리합니다.

프리뷰와 인큐베이터로 계속 가는 것들

JEP 내용 단계 이번에 달라진 점
JEP 531 Lazy Constants 프리뷰 3차 저수준 메서드 isInitialized·orElse 제거, Set.ofLazy(...) 추가
JEP 532 패턴·instanceof·switch의 기본형 타입 프리뷰 5차 변경 없음
JEP 533 Structured Concurrency 프리뷰 7차 스코프·Joiner에 세 번째 타입 파라미터, awaitAll() 제거, onTimeout() → timeout()
JEP 538 암호화 객체의 PEM 인코딩 프리뷰 3차 PEM이 record에서 일반 클래스로, DEREncodable → BinaryEncodable, CryptoException 신설
JEP 537 Vector API 인큐베이터 12차 API 변경 없음, 번들 SLEEF 3.6.1 → 3.9.0

프리뷰 넷은 기본이 꺼져 있는 preview API라 쓰려면 활성화가 필요하고 컴파일과 실행 양쪽에서 켜야 합니다 — JEP 532·533·538의 예제는 javac --release 27 --enable-preview입니다. 프리뷰는 릴리스마다 API가 갈리는 단계라는 점이 표에도 그대로 나옵니다. Structured Concurrency는 기본 조인 정책을 구현한 새 static open 메서드를 넣고 Joiner 팩토리가 결과가 예외일 때 join()이 ExecutionException을 던지도록 바꿨습니다. PEM은 Base64 바이트 배열을 받는 생성자를 PEM 클래스에 더하고 암호화 처리 실패를 나타내는 CryptoException을 새로 두었습니다.

차수는 발표 메일 표기와 각 JEP의 History 절을 맞춰 봤습니다. Structured Concurrency는 JEP 428(JDK 19)·437(20)의 인큐베이터를 거쳐 JEP 453(JDK 21)부터 프리뷰였고 453·462·480·499·505·525·533 일곱 차례입니다. 기본형 타입은 JEP 455(JDK 23)·488(24)·507(25)·530(26)에 이은 다섯 번째이고 이번에는 변경 없음입니다. Lazy Constants는 JDK 25의 JEP 502에서 시작해 JDK 26의 JEP 526에서 StableValue를 LazyConstant로 바꾼 이력이 있습니다.

Vector API(JEP 537)만 성격이 다릅니다. 인큐베이터라서 프리뷰가 아니고 preview 활성화와 무관하게 jdk.incubator.vector 모듈로 제공됩니다. JDK 16의 JEP 338부터 이번이 열두 번째이고 API 변경은 없으며 번들 SLEEF는 3.6.1에서 3.9.0으로 올라갑니다. JEP은 Valhalla의 필요 기능이 프리뷰로 제공될 때까지 인큐베이션을 계속한다고 적습니다.

JDK 27에서 프리뷰 또는 인큐베이터 단계인 다섯 JEP의 차수와 사용 방식을 정리한 표. 프리뷰 넷은 preview 활성화가 필요하고 Vector API만 jdk.incubator.vector 모듈로 구분돼 있다.

인큐베이터는 프리뷰와 사용 메커니즘이 다르다.

업그레이드할 때 확인할 것

첫째, 가비지 컬렉터를 지정한 적 없는 배포입니다. 특히 CPU가 적거나 메모리가 작게 잡힌 환경으로, JDK 26까지 규칙에서 Serial이 기본이던 곳이 JDK 27에서는 G1을 받습니다. 유지할 근거가 있으면 -XX:+UseSerialGC로 명시합니다.

둘째, 컴팩트 객체 헤더입니다. 기본이 켜지므로 옛 헤더 크기를 전제로 둔 힙 추정·메모리 한도·배포 밀도 계산은 수치가 달라집니다. 되돌리려면 -XX:-UseCompactObjectHeaders입니다.

셋째, JFR 리코딩의 소비처입니다. 기존 릴리스와 달리 명령행 인자·환경변수·시스템 프로퍼티 필드에 [REDACTED]가 나타날 수 있다는 것이 JEP 536이 Risks로 든 영향입니다. 리코딩에서 이 값들을 꺼 쓰는 도구가 있다면 기본 필터를 먼저 확인하고 필요하면 되돌리는 옵션을 둡니다.

넷째, TLS 1.3 클라이언트와 서버입니다. 클라이언트는 X25519MLKEM768과 x25519 두 키 셰어를 제공하고 하이브리드 그룹의 채택은 jdk.tls.namedGroups 속성 또는 SSLParameters::setNamedGroups로 조정합니다.

다섯째, 프리뷰 API에 의존하는 코드입니다. --enable-preview 없이는 컴파일·실행이 안 되고 릴리스를 옮기면 API 변경도 따라옵니다 — 이번에도 메서드 제거와 치환이 있었습니다.

JDK 27로 업그레이드하기 전 확인 항목 다섯 개를 화살표로 이은 체크리스트. GC 미지정 환경 점검에서 시작해 컴팩트 헤더, JFR 리코딩 소비처, TLS 키 셰어, 프리뷰 의존 코드까지 순서대로 나열돼 있다.

기본값이 바뀐 두 항목이 첫 두 칸이다.

기본값이 바뀐 두 항목(JEP 523·534)은 아무 설정도 하지 않은 배포에 적용되고 명시적 설정은 여전히 최우선입니다. 이 두 지점을 먼저 보고 나머지는 필요한 기능부터 확인하는 순서가 안전합니다.

근거와 참고

이 글 공유하기xXfacebook페이스북