JDK 27이 9월 15일 정식으로 나왔다. OpenJDK 프로젝트 페이지 문장 그대로 "JDK 27 reached General Availability on 15 September 2026"이고, 빌드는 35다. 6개월마다 나오는 릴리스라 "또 나왔구나" 하고 넘기기 쉬운데, 이번엔 옵션을 하나도 안 건드려도 동작이 바뀌는 항목이 셋 있다.

먼저 밝혀둘 것. 27은 LTS가 아니다. 오라클 로드맵 원문은 "Java SE 8, 11, 17, 21, and 25 are LTS releases"이고 다음 LTS는 2027년 9월 29로 예정돼 있다. 오라클 기준 27의 업데이트는 2027년 3월 JDK 28이 나올 때까지다. 그러니 운영 서버를 25에서 27로 올릴 이유는 별로 없고, 이 글은 "그래도 뭐가 바뀌었나"를 확인한 기록이다.
특히 유의해야 할 점은 아래 셋이 전부 기본값이라는 것이다. 예전처럼 플래그를 켜야 동작하는 게 아니라, 아무것도 안 하면 켜진 채로 뜬다.
직접 확인한 방법
시스템에 깔지 않고 tar.gz를 임시 폴더에 풀어 바이너리를 바로 실행했다. 비교 대상은 JDK 23이다.
# jdk.java.net/27 에서 받은 파일의 해시가 페이지 값과 같은지 확인하고 압축만 푼다
shasum -a 256 openjdk-27_macos-aarch64_bin.tar.gz
tar xzf openjdk-27_macos-aarch64_bin.tar.gz && cd jdk-27.jdk/Contents/Home
./bin/java -version
# openjdk version "27" 2026-09-15
# OpenJDK Runtime Environment (build 27+35-2325)
컴팩트 객체 헤더가 기본
JEP 534 "Compact Object Headers by Default"다. 객체 헤더를 96비트에서 64비트로 줄이는 레이아웃인데, 24에서 실험 기능으로 들어와 25에서 정식 기능이 됐고, 27부터 기본이다. 25에서는 -XX:+UseCompactObjectHeaders를 직접 켜야 했다.
# 27에서 플래그 기본값을 찍어본다. {default}면 손대지 않은 값이다
./bin/java -XX:+PrintFlagsFinal -version | grep -iE 'UseCompactObjectHeaders|UseG1GC|UseSerialGC|UseZGC'
# bool UseCompactObjectHeaders = true {product lp64_product} {default}
# bool UseG1GC = true {product} {ergonomic}
# bool UseSerialGC = false {product} {default}
JDK 23에서는 같은 명령을 쳐도 UseCompactObjectHeaders 항목 자체가 안 나온다. 예전 레이아웃으로 돌리려면 -XX:-UseCompactObjectHeaders를 주면 되고, 실제로 주면 {command line} 표시와 함께 false로 바뀌는 걸 확인했다. 힙 덤프를 뜯거나 오프셋에 기대는 에이전트를 쓰는 프로젝트라면 이 부분부터 봐야 한다.
1코어 컨테이너에서도 G1
JEP 523이다. 25까지는 CPU가 하나거나 메모리가 1792MB 미만인 환경에서 Serial GC가 유리하다고 보고 JVM이 Serial을 골랐다. 27부터는 원문대로 "the JVM will always select G1, regardless of the number of processors and the available physical memory"다. G1이 이제 모든 힙 크기에서 Serial과 경쟁할 만하다는 게 이유로 적혀 있다.
# CPU를 1개로 제한하고 어떤 GC를 고르는지 본다
./bin/java -XX:ActiveProcessorCount=1 -XX:+PrintCommandLineFlags -version
# 27: ... -XX:ConcGCThreads=1 -XX:G1ConcRefinementThreads=1 ... -XX:+UseG1GC ...
# 23: ... -XX:+UseSerialGC ...
작은 컨테이너에 자바를 넣어 돌리던 사람은 GC가 바뀐 채 뜨게 된다. 굳이 Serial을 유지하고 싶으면 -XX:+UseSerialGC를 명시하면 된다.
TLS 1.3에 양자내성 키교환이 앞줄로
JEP 527이다. TLS 1.3 핸드셰이크에서 X25519MLKEM768이라는 하이브리드 그룹을 기본 목록 맨 앞에 둔다. SSLContext의 기본 파라미터에서 이름 목록을 찍어 보니 27은 X25519MLKEM768, x25519, secp256r1, ...으로 시작하고, 23은 x25519부터 시작한다. 기본 목록의 순서만 바뀐 것이라 코드에서 그룹을 직접 지정해 둔 게 아니면 손댈 곳은 없다.
덤으로 들어온 것과 프리뷰
JEP 536은 JFR 녹화에서 명령줄 인자와 환경변수 값을 추가 설정 없이 기본으로 마스킹한다. -XX:FlightRecorderOptions=help를 치면 *password*, *token*, *secret* 같은 기본 필터 목록이 나온다. 프리뷰로 남은 건 구조적 동시성 7차, 패턴의 원시 타입 5차, Lazy Constants 3차, PEM 3차이고, Vector API는 12번째 인큐베이터다. LazyConstant를 --enable-preview 없이 돌리면 "preview API and is disabled by default" 에러가 난다.
올리다 걸린 것
-XX:MaxRAM=1g를 주면 "Ignoring option MaxRAM; support was removed in 27.0" 경고가 뜬다. 23에서는 경고 없이 받던 옵션이다. 기동 스크립트에 이 옵션이 박혀 있으면 지우자.
JDK 버전 올리기는 자동차 검사와 비슷하다. 겉으로는 똑같이 굴러가는데 정비소가 바꿔 놓은 설정이 있다. 웬만하면 컨테이너 이미지의 기동 옵션을 열어 GC 지정, 헤더 플래그, MaxRAM 세 줄이 있는지부터 훑어보자. 그것만 해도 27로 올린 뒤 새벽에 깨어날 일은 줄어든다.
참고
- OpenJDK, JDK 27 https://openjdk.org/projects/jdk/27/
- JEP 534, Compact Object Headers by Default https://openjdk.org/jeps/534
- JEP 523, Make G1 the Default Garbage Collector in All Environments https://openjdk.org/jeps/523
- JEP 527, Post-Quantum Hybrid Key Exchange for TLS 1.3 https://openjdk.org/jeps/527
- Oracle Java SE Support Roadmap https://www.oracle.com/java/technologies/java-se-support-roadmap.html
'개발 > 백엔드' 카테고리의 다른 글
| 🪟 윈도우10 ESU 연장 · 2027년 10월 12일까지 받는 법 (0) | 2026.10.26 |
|---|---|
| 🟩 Node.js 26 LTS 10월 28일 · 22는 2027년 4월 종료 (0) | 2026.10.25 |
| [백엔드] 🔑 Dockerfile ARG로 넘긴 토큰은 docker history에 그대로 남는다 (1) | 2026.09.18 |
| 🔐 개정 개인정보보호법 9월 11일 시행, 서비스 운영자가 바꿀 것 4가지 (1) | 2026.09.11 |
| ⏰ 맥 launchd vs cron, 자동 실행 뭘로 하나 (1) | 2026.09.10 |