Contents
see List2025년 3월에 출시된 JDK 24는 24개의 JEP(JDK Enhancement Proposal)를 포함하는 대규모 릴리스다. 그중에서도 Compact Object Headers(JEP 450)는 JVM 성능에 근본적인 변화를 가져오는 기능이다. 64비트 아키텍처에서 객체 헤더 크기를 96~128비트에서 64비트로 줄여, 힙 메모리를 최대 25%까지 절약할 수 있다.
객체 헤더란 무엇인가
Java에서 모든 객체는 실제 필드 데이터 외에 객체 헤더(Object Header)를 가진다. HotSpot JVM의 기존 객체 헤더는 두 부분으로 구성된다.
기존 구조 (96~128비트)
// 기존 객체 헤더 구조 (64비트 JVM)
+--------------------------------------------------+
| Mark Word (64비트) |
| - 해시코드, GC 나이, 잠금 상태 등 |
+--------------------------------------------------+
| Klass Pointer (32비트, 압축 시 / 64비트, 비압축 시) |
| - 객체의 클래스 메타데이터 포인터 |
+--------------------------------------------------+
| 배열 길이 (배열 객체인 경우 추가 32비트) |
+--------------------------------------------------+
// 최소 객체 크기 계산
// 헤더: 12바이트 (Mark 8 + Klass 4, 압축 포인터)
// 패딩: 4바이트 (8바이트 정렬)
// 최소 객체 크기: 16바이트
Compact Object Headers (64비트)
// JEP 450 - Compact Object Headers
+--------------------------------------------------+
| Compact Header (64비트) |
| - Mark Word + Klass Pointer 통합 |
| - 해시코드, GC 나이, 잠금 상태, 클래스 포인터 압축 |
+--------------------------------------------------+
// 최소 객체 크기: 8바이트 (헤더만)
// 실제로는 8바이트 정렬로 인해 차이 발생
활성화 방법
JDK 24에서 Compact Object Headers는 실험적 기능으로 제공되며, 명시적으로 활성화해야 한다.
# Compact Object Headers 활성화
java -XX:+UnlockExperimentalVMOptions \
-XX:+UseCompactObjectHeaders \
-jar myapp.jar
# 현재 객체 헤더 크기 확인
java -XX:+UnlockExperimentalVMOptions \
-XX:+UseCompactObjectHeaders \
-XX:+PrintFieldLayout \
MyClass
실제 메모리 절약 효과 측정
JOL(Java Object Layout) 도구를 사용하여 실제 메모리 절약 효과를 확인할 수 있다.
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.info.GraphLayout;
public class MemoryAnalysis {
// 간단한 도메인 객체
static class User {
private long id;
private String name;
private int age;
}
public static void main(String[] args) {
User user = new User();
// 단일 객체의 레이아웃 출력
System.out.println(ClassLayout.parseInstance(user).toPrintable());
// 기존 헤더: User 객체 = 32바이트
// Mark(8) + Klass(4) + id(8) + name(4, ref) + age(4) + padding(4)
// Compact 헤더: User 객체 = 24바이트
// Header(8) + id(8) + name(4, ref) + age(4)
// 25% 절약!
// 대량 객체 테스트
User[] users = new User[1_000_000];
for (int i = 0; i < users.length; i++) {
users[i] = new User();
}
System.out.println("Total footprint: " +
GraphLayout.parseInstance((Object) users).totalSize() + " bytes");
}
}
Maven에 JOL 의존성 추가
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.17</version>
</dependency>
Java 24의 다른 핵심 기능들
양자 내성 암호화 (JEP 496, 497)
양자 컴퓨터 시대를 대비한 새로운 암호화 알고리즘이 도입되었다.
import java.security.KeyPairGenerator;
import javax.crypto.KEM;
// ML-KEM (Module-Lattice-Based Key Encapsulation)
// 양자 내성 키 캡슐화 메커니즘
KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-KEM");
kpg.initialize(java.security.spec.NamedParameterSpec.ML_KEM_768);
var keyPair = kpg.generateKeyPair();
// 키 캡슐화
KEM kem = KEM.getInstance("ML-KEM");
KEM.Encapsulator enc = kem.newEncapsulator(keyPair.getPublic());
KEM.Encapsulated encapsulated = enc.encapsulate();
byte[] sharedSecret = encapsulated.key().getEncoded();
byte[] ciphertext = encapsulated.encapsulation();
// 키 역캡슐화
KEM.Decapsulator dec = kem.newDecapsulator(keyPair.getPrivate());
byte[] recovered = dec.decapsulate(ciphertext).getEncoded();
생성자 내 사전 실행문 (JEP 482, Preview)
생성자에서 super() 또는 this() 호출 전에 문장을 실행할 수 있다.
// Java 24 이전: 생성자 첫 줄은 반드시 super() 또는 this()
class OldStyle extends Parent {
OldStyle(String rawData) {
super(validate(rawData)); // static 메서드로 우회해야 했음
}
private static String validate(String data) {
if (data == null) throw new IllegalArgumentException();
return data.trim();
}
}
// Java 24 (Preview): 사전 실행문 허용
class NewStyle extends Parent {
NewStyle(String rawData) {
// super() 전에 유효성 검사 가능
if (rawData == null) {
throw new IllegalArgumentException("데이터가 null입니다");
}
String cleaned = rawData.trim();
// 필드 초기화도 가능 (인스턴스 참조 불가)
super(cleaned);
}
}
모듈 임포트 선언 (JEP 494, Preview)
// 기존: 개별 패키지 임포트
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.io.IOException;
// Java 24 (Preview): 모듈 단위 임포트
import module java.base; // java.base 모듈의 모든 공개 패키지
import module java.sql; // java.sql 모듈의 모든 공개 패키지
public class ModuleImportDemo {
public static void main(String[] args) {
// List, Map, Collectors 등 별도 임포트 없이 사용
List names = List.of("Alice", "Bob", "Charlie");
Map map = names.stream()
.collect(Collectors.toMap(String::length, s -> s, (a, b) -> a));
}
}
원시 타입 패턴 매칭 (JEP 488, Preview)
// switch에서 원시 타입 패턴 매칭
static String classify(Object obj) {
return switch (obj) {
case int i when i > 0 -> "양의 정수: " + i;
case int i when i < 0 -> "음의 정수: " + i;
case int i -> "영";
case double d when d > 0 -> "양의 실수: " + d;
case long l -> "long: " + l;
case String s -> "문자열: " + s;
default -> "기타: " + obj;
};
}
// instanceof에서 원시 타입
Object value = getFromDB();
if (value instanceof int count) {
System.out.println("정수 카운트: " + count);
} else if (value instanceof double ratio) {
System.out.println("비율: " + ratio);
}
JDK 24 적용 시 주의사항
- JDK 24는 비LTS 릴리스로 6개월간 프리미어 지원만 제공된다. 프로덕션에는 JDK 21 LTS 또는 차기 LTS(JDK 25)를 권장한다.
- Compact Object Headers는 실험적 기능이므로 충분한 테스트 후 적용해야 한다.
- Windows 32비트 x86 포트가 제거되었으므로 해당 환경 사용자는 주의가 필요하다.
- Preview 기능은
--enable-preview플래그를 추가해야 사용할 수 있다.