JDK 26의 위치
2026년 3월 17일 출시된 JDK 26은 10개의 JEP을 포함한 비LTS 릴리스입니다. JEP 수는 JDK 24(24개)에 비해 적지만, HTTP/3 지원(JEP 517)과 G1 GC 처리량 향상(JEP 522)이라는 실무 밀접 기능이 포함되어 있습니다. 또한 Java 언어의 장기 방향성을 보여주는 Prepare to Make Final Mean Final(JEP 500)이 주목할 만합니다.
HTTP/3 for HttpClient API (JEP 517, 정식)
JDK 11에서 도입된 HttpClient가 드디어 HTTP/3를 지원합니다. HTTP/3는 TCP 대신 QUIC 프로토콜을 사용하며, 패킷 손실 시 다른 스트림에 영향을 주지 않는 Head-of-Line Blocking 해결, 연결 수립 시간 단축(0-RTT), 네트워크 전환 시 연결 유지(Connection Migration) 등의 이점이 있습니다.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class Http3Demo {
public static void main(String[] args) throws Exception {
// HTTP/3를 지원하는 HttpClient 생성
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_3) // HTTP/3 명시
.connectTimeout(Duration.ofSeconds(10))
.build();
// HTTP/3 요청 생성
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://www.google.com"))
.GET()
.build();
// 요청 전송 및 응답 수신
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString()
);
System.out.println("=== HTTP/3 응답 정보 ===");
System.out.println("상태 코드: " + response.statusCode());
System.out.println("프로토콜: " + response.version());
System.out.println("응답 크기: " + response.body().length() + " chars");
// 출력 예시:
// === HTTP/3 응답 정보 ===
// 상태 코드: 200
// 프로토콜: HTTP_3
// 응답 크기: 14523 chars
// 헤더 출력
response.headers().map().forEach((key, values) -> {
if (key.startsWith("content") || key.startsWith("server")) {
System.out.println(key + ": " + values);
}
});
}
}
HTTP/3 사용 시 알아야 할 점이 있습니다. 서버가 HTTP/3를 지원하지 않으면 자동으로 HTTP/2 또는 HTTP/1.1로 폴백(fallback) 합니다. 기존 코드에서 HttpClient.Version.HTTP_2를 HTTP_3로 변경하는 것만으로 업그레이드가 가능하며, 서버 호환성 걱정 없이 적용할 수 있습니다.
| 프로토콜 | 전송 계층 | 주요 특징 |
|---|---|---|
| HTTP/1.1 | TCP | 순차 요청/응답 |
| HTTP/2 | TCP | 멀티플렉싱, 헤더 압축, 서버 푸시 |
| HTTP/3 | QUIC (UDP) | HoL Blocking 해결, 0-RTT, 연결 마이그레이션 |
G1 GC Improve Throughput (JEP 522)
JDK 26에서 기본 GC인 G1의 처리량이 최대 15% 향상됩니다. G1은 JDK 9부터 기본 GC로 대부분의 Java 애플리케이션이 사용하고 있으므로, 이 개선은 별도 설정 없이 거의 모든 프로젝트에 적용됩니다.
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class G1ThroughputDemo {
public static void main(String[] args) {
// G1 GC 처리량 테스트: 대량 객체 할당 및 해제 시뮬레이션
// 실행: java -verbose:gc G1ThroughputDemo
Random random = new Random(42);
List<byte[]> liveObjects = new ArrayList<>();
int totalAllocated = 0;
long start = System.nanoTime();
for (int cycle = 0; cycle < 100; cycle++) {
// 객체 할당: 다양한 크기의 바이트 배열 생성
for (int i = 0; i < 1000; i++) {
int size = random.nextInt(1024, 65536); // 1KB ~ 64KB
liveObjects.add(new byte[size]);
totalAllocated++;
}
// 객체 해제: 70%를 제거하여 GC 유도 (약한 세대 가설 시뮬레이션)
int removeCount = (int) (liveObjects.size() * 0.7);
for (int i = 0; i < removeCount; i++) {
liveObjects.remove(liveObjects.size() - 1);
}
}
long elapsed = (System.nanoTime() - start) / 1_000_000;
System.out.println("=== G1 GC 처리량 테스트 ===");
System.out.println("총 할당 객체: " + totalAllocated);
System.out.println("생존 객체: " + liveObjects.size());
System.out.println("소요 시간: " + elapsed + "ms");
System.out.println();
System.out.println("JDK 26 G1 개선 사항:");
System.out.println(" - 처리량 최대 15% 향상");
System.out.println(" - Remembered Set 최적화");
System.out.println(" - Write Barrier 효율화");
// 출력 예시:
// === G1 GC 처리량 테스트 ===
// 총 할당 객체: 100000
// 생존 객체: 811
// 소요 시간: 2340ms
//
// JDK 26 G1 개선 사항:
// - 처리량 최대 15% 향상
// - Remembered Set 최적화
// - Write Barrier 효율화
}
}
G1 처리량 개선은 Remembered Set 관리와 Write Barrier 최적화를 통해 이루어졌습니다. Remembered Set은 Old 세대에서 Young 세대를 참조하는 포인터를 추적하는 자료구조인데, 이 관리 비용이 줄어들면서 애플리케이션 스레드가 더 많은 CPU 시간을 확보하게 됩니다.
AOT Object Caching with Any GC (JEP 516)
JDK 24에서 도입된 AOT 클래스 로딩(JEP 483)이 한 단계 더 발전했습니다. JDK 26에서는 AOT 객체 캐싱이 모든 GC와 호환됩니다. 이전에는 특정 GC에서만 AOT 캐시를 사용할 수 있었지만, 이제 G1, ZGC, Shenandoah, Serial, Parallel 어떤 GC를 사용하더라도 AOT 캐시의 이점을 누릴 수 있습니다.
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class AotCachingDemo {
// AOT 캐싱 효과 시뮬레이션
// 실행 1회차: java -XX:AOTCache=app.aotcache -XX:AOTMode=record AotCachingDemo
// 실행 2회차: java -XX:AOTCache=app.aotcache -XX:AOTMode=on AotCachingDemo
public static void main(String[] args) {
long startTime = System.nanoTime();
// 일반적인 애플리케이션 초기화 코드
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String now = LocalDateTime.now().format(formatter);
// 클래스 로딩 + 링킹이 필요한 작업
var list = java.util.stream.IntStream.range(0, 1000)
.boxed()
.toList();
long elapsedMs = (System.nanoTime() - startTime) / 1_000_000;
System.out.println("=== AOT Object Caching 효과 ===");
System.out.println("현재 시각: " + now);
System.out.println("초기화 시간: " + elapsedMs + "ms");
System.out.println("리스트 크기: " + list.size());
System.out.println();
System.out.println("JDK 26 AOT 변화:");
System.out.println(" - 모든 GC에서 AOT 캐시 사용 가능");
System.out.println(" - G1, ZGC, Shenandoah, Serial, Parallel 모두 지원");
System.out.println(" - 재시작 시 클래스 로딩/링킹 비용 절감");
// 출력 예시:
// === AOT Object Caching 효과 ===
// 현재 시각: 2026-04-07 14:30:00
// 초기화 시간: 45ms
// 리스트 크기: 1000
//
// JDK 26 AOT 변화:
// - 모든 GC에서 AOT 캐시 사용 가능
// - G1, ZGC, Shenandoah, Serial, Parallel 모두 지원
// - 재시작 시 클래스 로딩/링킹 비용 절감
}
}
AOT 캐싱은 특히 마이크로서비스 환경에서 효과적입니다. 컨테이너가 재시작될 때마다 클래스를 새로 로딩하고 JIT 워밍업을 거쳐야 하는 Cold Start 문제를 캐시로 완화할 수 있기 때문입니다.
그 외 주목할 JEP
Prepare to Make Final Mean Final (JEP 500): final 키워드의 의미를 강화하는 장기 프로젝트의 첫 단계입니다. 현재 Java에서는 리플렉션이나 Unsafe를 통해 final 필드를 수정할 수 있는데, 이를 점진적으로 차단하겠다는 방향입니다. Hibernate, Jackson 같은 프레임워크가 final 필드를 리플렉션으로 수정하는 패턴을 사용하고 있으므로, 라이브러리 호환성을 확인할 필요가 있습니다.
Applet API 완전 제거 (JEP 504): 1995년 Java 1.0부터 존재하던 Applet API가 완전히 제거됩니다. java.applet 패키지와 관련 클래스가 삭제되며, 이미 JDK 9에서 deprecated 되었으므로 영향을 받는 프로젝트는 거의 없을 것입니다. 30년간 유지된 레거시의 공식적인 퇴장입니다.
JDK 23~26 GC 진화 타임라인
JDK 23부터 26까지의 GC 관련 변화를 정리하면 방향성이 명확합니다.
| 버전 | GC 변화 |
|---|---|
| JDK 23 | ZGC 세대별 모드 기본값 전환 |
| JDK 24 | ZGC 비세대별 모드 제거, G1 Late Barrier Expansion |
| JDK 25 | Compact Object Headers 정식 (힙 22%↓), Shenandoah 세대별 정식 |
| JDK 26 | G1 처리량 15%↑, AOT 캐시 모든 GC 지원 |
세대별 GC로의 통합, 객체 헤더 압축, G1 최적화라는 세 축이 동시에 진행되고 있으며, JDK 26에서 이 방향의 성과가 결실을 맺고 있습니다.
실전 팁
| 기능 | 상태 | 핵심 포인트 |
|---|---|---|
| HTTP/3 | 정식 | HttpClient.Version.HTTP_3, 자동 폴백 |
| G1 처리량 향상 | 정식 | 최대 15% 처리량 개선, 설정 변경 불필요 |
| AOT 캐시 확장 | 정식 | 모든 GC에서 AOT 객체 캐싱 |
| Final 강화 준비 | 정식 | final 필드 리플렉션 수정 점진적 차단 |
| Applet API 제거 | 정식 | java.applet 패키지 완전 삭제 |
JDK 26에서 가장 임팩트가 큰 변화는 G1 GC 처리량 향상입니다. 대부분의 Java 애플리케이션이 G1을 기본으로 사용하므로, JDK 업그레이드만으로 성능 개선 효과를 얻을 수 있습니다. HTTP/3 지원도 높은 지연 환경이나 모바일 네트워크에서 유의미한 차이를 만들어주므로, HttpClient를 사용하는 프로젝트라면 버전 옵션 하나 변경으로 적용해볼 만합니다.