Java Valhalla: Mười Hai Năm Để Xóa Một Giả Định
Sau một thập kỷ, Project Valhalla cuối cùng đã vào JDK 28 dạng preview. Cả dự án rút lại còn một ý: cho phép object từ bỏ identity để JVM xếp gọn như int.

Hồi xưa tôi phải làm một service Java xử lý hàng triệu object toạ độ bé tí cho nhanh. Profiler cứ chỉ vào đúng một chỗ: cache miss. Không phải code tôi dở. Là cái hình dạng dữ liệu của tôi.
Thế là tôi làm cái việc mà dân Java ai cũng làm khi tốc độ quan trọng hơn lòng tự trọng. Tôi xoá cái class Point đẹp đẽ, thay bằng hai mảng int[] thô, một cho x một cho y. Nhanh thật. Mà cũng là một cái đầm lầy. Lộn index một lần thôi là dữ liệu hỏng âm thầm, không ai báo.
Cái đầm lầy đó chính là thứ Project Valhalla bỏ ra mười hai năm để tát cạn.
Câu chuyện gói trong một câu
Ngày 15 tháng 6, kỹ sư Oracle Lois Foltan xác nhận: JEP 401, Value Classes and Objects, đang được merge vào repo chính của OpenJDK, nhắm JDK 28. Thay đổi lớn tới mức các committer khác bị nhờ tạm ngừng commit lớn trong lúc nó vào. Riêng pull request đã hơn 197.000 dòng trên 1.816 file.
Tất cả đống đó mua cho bạn cái gì? Một từ trong source code.
value class Point {
final int x;
final int y;
Point(int x, int y) { this.x = x; this.y = y; }
}
Point[] points = new Point[1_000_000];
Khác với một class bình thường đúng mỗi cái từ value. Nhưng khác biệt trong bộ nhớ thì là cả vấn đề.
“value” thật ra đổi cái gì
Từ năm 1995, mọi object Java trừ tám primitive đều có identity. Khi bạn viết Point p = new Point(1, 2), p không phải là một điểm. Nó là cái số phiếu giữ đồ. Object thật nằm đâu đó trên heap, và mỗi lần đọc field là một cú nhảy qua con trỏ đó.
Một object thì cú nhảy đó miễn phí. Một triệu object thì là một triệu cái phiếu chỉ tới một triệu cái hộp rải khắp kho. Brian Goetz gọi cách bố trí đó là “fluffy” · phồng, xốp. CPU đọc bộ nhớ theo từng cache line 64 byte, và một layout xốp phí gần hết mỗi line cho việc đuổi theo con trỏ với header của từng object.
Một value class không có identity. Không có chuyện “hai bản khác nhau” của new Point(1,2), y như không có hai con số 4 khác nhau. Bỏ identity đi, JVM tự nhiên được tự do xếp thẳng các giá trị nằm cạnh nhau, không header, không con trỏ.
Giờ khi lặp qua mảng, processor đọc tuần tự. Mỗi cache line kéo về luôn vài điểm trọn vẹn. Với vòng lặp nặng dữ liệu, đó là khác biệt theo lần, không phải theo phần trăm. Mà bạn vẫn giữ được class: cái tên, constructor, validation, các method. Bạn có độ dày của primitive và độ dễ đọc của class.
Tại sao một bài mổ xẻ ruột JVM lại lên front page
Vì cái câu đùa. Bao năm nay cộng đồng nói rằng tất cả tụi mình sẽ tới Valhalla, cái Valhalla cõi âm của Bắc Âu ấy, trước khi dự án này ship. Goetz tự đoán luôn rằng đám “tụi nó không bao giờ ship đâu” sẽ lập tức quay xe sang “nhưng nó đâu có ship cái phần quan trọng nhất”. Ổng nói đúng, và đúng cái căng đó là một nửa của thread.
Nó lên còn vì bản trung thực của tiêu đề là một nửa sự thật. “Valhalla vào JDK 28” nghe như đã tới đích. Thật ra là preview, mặc định tắt, và mới chỉ là giai đoạn đầu. Kiểu non-null, generics đặc biệt hoá, mã hoá 128-bit, ArrayList phẳng trên value type: không cái nào có trong 28. JDK 28 còn chẳng phải LTS, nên đa số công ty sẽ chỉ gặp một Valhalla ổn định quanh JDK 29 cuối 2027.
HN đang cãi nhau về cái gì
Câu phản bác sắc nhất tới từ rf15, phản ứng với chỗ bài viết gọi mô hình hai phép chiếu cũ là “nặng đầu”:
“Không hề nặng! … Chẳng có lý do gì để cắt bớt cái bảo đảm an toàn tuỳ chọn mà bạn có thể cung cấp, chỉ với cái cớ ‘quá nặng đầu’.”
Đó mới là cuộc chiến thật. Team giết cái dualism Point.val / Point.ref để giữ ngôn ngữ cho đơn giản, và tách chuyện non-null ra một JEP riêng cho tương lai. Có người muốn cái null-safety đó nướng vào ngay bây giờ, và đọc sự đơn giản hoá đó như một bước lùi.
layer8 tìm ra một cái bẫy tinh vi hơn: với value object, == giờ so sánh đệ quy toàn bộ field, về cơ bản là một cú memcmp. Cái đó có thể phơi ra biểu diễn nội bộ mà lẽ ra equals đã giấu đi.
Còn tomaytotomato thì bênh cả đám bằng một ẩn dụ nuôi con: Java được cha mẹ thương yêu nuôi nấng buổi đầu (Sun), rồi bị một ông giám hộ ác quăng vào nhà kho bỏ bê (Oracle), và từ đó cứ phải chạy theo cho kịp. Phũ, mà thương, và rất HN.
Comment tôi khoái nhất lại chẳng phải tranh luận gì. smallnix để ý cái placeholder [IMAGE: ...] trong bài và phán tỉnh bơ rằng cái Point[] trong prompt đã làm sập trình sinh ảnh LLM của tác giả. Một bài về làm phẳng mảng, bị hạ bởi một cái mảng nằm trong chuỗi.
Có nên đọc bản gốc không
| Đọc nếu… | Bỏ qua nếu… |
|---|---|
Bạn viết Java và muốn hiểu mô hình thật sau từ value |
Bạn chỉ quan tâm khi nó là mặc định LTS (đợi JDK 29) |
| Bạn từng tẩu hoả với mớ tên gọi đổi tới đổi lui của nó | Bạn vốn đã theo dõi mailing list của OpenJDK |
| Bạn làm data, ML, gamedev, hay tài chính trên JVM | Bạn không kiểm soát các điểm nóng allocation trong code |
Bài viết là tấm bản đồ rõ nhất về cả một thập kỷ prototype chết yểu mà tôi từng đọc: Q World, L World, value types, inline classes, primitive classes, rồi cuối cùng chỉ còn value classes.
Đây là chỗ làm tôi nhớ mãi. Mười hai năm không phải mười hai năm ngồi viết code. Là mười hai năm vứt bỏ ý tưởng cho tới khi còn lại đúng một cái có thể nuôi nổi. Thứ ship ra là một từ khoá. Còn công sức nằm ở chỗ quyết định cái giả định nào, đúng từ 1995, mà họ cuối cùng được phép xoá.
Cái service cũ với hai mảng int[] của tôi vẫn còn nằm đâu đó. Một ngày nào đó tôi sẽ được xoá cái đầm lầy và viết value class thay vào. Tôi chỉ phải đợi LTS thôi, như mọi người đã đợi Valhalla.
Thảo luận trên Hacker News · Nguồn: jvm-weekly.com · Đăng bởi philonoist
Bài viết liên quan
DuckDB nhanh vì nó bỏ qua cái khúc ai cũng quên
Mổ xẻ bên trong DuckDB: vì sao một engine SQL chạy ngay trong tiến trình, bỏ qua mạng, lại nhanh hơn cả cụm máy chủ triệu đô, và dân HN nghĩ gì.
Bốn Thay Đổi Nhỏ Trong Python 3.15 Mà Ít Ai Để Ý
Python 3.15 có lazy imports và Tachyon profiler đình đám, nhưng bốn tính năng thực sự hữu ích lại là TaskGroup.cancel(), context manager decorator sửa đúng,…
XS: Một binary 2.9 MB chứa cả một toolchain lập trình
XS gói gọn compiler, debugger, formatter, package manager và 6 backend vào một binary 2.9 MB, chạy được trên Linux, macOS, ESP32 và nhiều nền tảng khác.
AutoResearch Giải Thích: Vì Sao Karpathy Đóng Góp Cho AI Scientist Này
Mổ xẻ AutoResearch: kiến trúc AI scientist đa mô hình, cơ chế Ralph loop hồi phục trạng thái và lý do Karpathy trực tiếp đóng góp vào repo.