JDK 27’de Evrensel G1 GC (JEP 523) ve TLAB İyileştirmeleri, Modern Java Güvenli Kodlama İlkeleri ve Spring Boot’ta jOOQ ‘MULTISET’ Mimarisi
Oracle HotSpot GC ekibinden Thomas Schatzl’ın paylaştığı JDK 27 G1/Parallel/Serial çöp toplayıcı değişiklikleri (JEP 523, Min/MaxHeapFreeRatio 0/100 ve JDK-8381834 TLAB optimizasyonu), SecurityManager sonrası güncellenen Java Secure Coding Guidelines ve Spring Boot’ta jOOQ MULTISET ile tip güvenli SQL projeksiyonları inceleniyor.

1. JDK 27 G1, Parallel ve Serial GC Değişiklikleri: JEP 523, Yığın Oranları ve TLAB Optimizasyonu
Oracle HotSpot Çöp Toplama (Garbage Collection - GC) ekibi üyesi Thomas Schatzl, Inside.java üzerinden yayımladığı "JDK 27 G1/Parallel/Serial GC changes" raporunda OpenJDK'nın duraklatmalı (stop-the-world) çöp toplayıcılarında gerçekleştirilen yaklaşık 350 mühendislik iyileştirmesini ve mimari sadeleştirmeyi detaylandırdı. JDK 27 ile birlikte özellikle konteyner tabanlı mikroservislerin bellek davranışını doğrudan etkileyen üç temel değişiklik öne çıkıyor:
A. JEP 523 ile G1 Her Ortamda Evrensel Varsayılan Çöp Toplayıcı
Önceki JDK sürümlerinde JVM, düşük işlemci çekirdeği veya küçük bellek sınırı tanımlanmış konteyner ortamlarında (örneğin 1 vCPU ve <2 GB RAM) otomatik olarak Serial GC'ye geri dönüyordu (fallback). Yıllar içinde G1'in yerel bellek ayak izinde (native memory footprint), bariyer senkronizasyonunda ve iş hacminde (throughput) yapılan optimizasyonlar sonucunda JEP 523 devreye alındı. Artık donanım veya konteyner boyutu ne olursa olsun G1 tüm dağıtım ortamlarında koşulsuz varsayılan GC olarak çalışıyor.
B. -XX:MinHeapFreeRatio ve -XX:MaxHeapFreeRatio Değerlerinin 0 ve 100 Yapılması
G1 çöp toplayıcısında uzun yıllardır sırasıyla 40 ve 70 olarak gelen -XX:MinHeapFreeRatio ve -XX:MaxHeapFreeRatio varsayılanları, JDK 27'de 0 ve 100 olarak değiştirildi:
- Eski Davranışın Sorunu: Uygulama
System.gc()çağırdığında veya bir Full GC gerçekleştiğinde, boş yığın oranı %70'in üzerindeyse G1 yığını agresif biçimde küçültüyor, %40'ın altındaysa genişletiyordu. Bu durum üretim ortamlarında gereksiz yığın yeniden boyutlandırma fırtınalarına (heap resizing storms) ve işletim sistemi sayfası (OS page) dalgalanmalarına yol açıyordu. - Yeni Davranış: Sabit yüzde eşikleri devre dışı bırakılarak yığın boyutlandırması tamamen GC/uygulama CPU süresi oranı (
GCTimeRatio) gibi akıcı sezgisel (heuristic) metriklere devredildi.
C. Kısa Ömürlü İş Parçacıkları İçin TLAB Boyutlandırması (JDK-8381834) ve Atomic<T> Geçişi
Çok sayıda kısa ömürlü ve az bellek ayıran iş parçacığı (short-lived, lightly-allocating threads) oluşturan uygulamalarda TLAB (Thread-Local Allocation Buffer) boyutlandırma algoritması güncellendi (JDK-8381834). Yeni algoritma, TLAB tamponlarının aşırı büyük ayrılmasını önleyerek genç nesil (young generation) bellek israfını ve erken GC tetiklenmelerini ortadan kaldırıyor. Ayrıca HotSpot C++ çekirdeğinde iş parçacıkları arası paylaşılan değişkenler geleneksel volatile + AtomicAccess kalıbından tip güvenli Atomic<T> sarmalayıcılarına taşındı.
[!IMPORTANT]
Konteyner Dağıtım Etkisi: Kubernetes üzerinde küçük CPU/RAM limitleriyle çalışan Java servislerinde JEP 523 sayesinde beklenmedikSerial GCduraklamaları sona ermekte;MinHeapFreeRatio=0/MaxHeapFreeRatio=100güncellemesiyle de Full GC sonrası ani RSS bellek dalgalanmaları engellenmektedir.
2. Modern Java ‘Secure Coding Guidelines’ Güncellemesi: SecurityManager Sonrası Savunma Mimarisi
Inside.java tarafından yayımlanan güncel Java Secure Coding Guidelines (Java SE Güvenli Kodlama İlkeleri) incelemesi, Java 17'de kullanımdan kaldırılan (deprecated) ve Java 24'te kalıcı olarak devre dışı bırakılan SecurityManager sonrasında güvenli yazılım mimarisinin nasıl kurgulanması gerektiğini ortaya koyuyor.
Güncel kılavuz, JVM içi çalışma zamanı kum havuzu (sandbox) yerine işletim sistemi/konteyner izolasyonu, JPMS modül sınırları ve veri odaklı doğrulama üzerine odaklanıyor:
flowchart LR
A["Güvenilmeyen Dış Girdi<br/>(Byte Akışı / XML / JSON / API)"] --> B["1. Sınır & DoS Koruması<br/>(Math.addExact, Boyut ve Derinlik Limiti)"]
B --> C["2. JEP 415 Serileştirme Filtresi<br/>(ObjectInputFilter Beyaz Liste Doğrulaması)"]
C --> D["3. Değişmez Veri & TOCTOU Koruması<br/>(Java Record, List.copyOf ve Savunmacı Kopyalama)"]
D --> E["4. Tip Güvenli Veritabanı Katmanı<br/>(Spring Boot + jOOQ MULTISET Derleme Zamanı SQL)"]
- Güvenilmeyen Deserialization ve JEP 415 Filtreleri: Java serileştirmesi en yüksek riskli saldırı vektörü olmaya devam ediyor. Kılavuz, ikili (binary) serileştirme yerine JSON/Protobuf gibi yapılandırılmış formatları; yerel serileştirme zorunluysa JEP 415 bağlama özgü
ObjectInputFilterbeyaz listelerini (maxdepth,maxInputSize,maxarray) zorunlu tutuyor. - Değişmezlik (Immutability) ve TOCTOU Koruması: Doğrulama zamanı ile kullanım zamanı arasındaki (Time-of-Check to Time-of-Use - TOCTOU) yarış durumu zafiyetlerini önlemek için değiştirilebilir (mutable) girdi ve çıktıların
List.copyOf()ile savunmacı biçimde kopyalanması ve veri taşıyıcıların değişmez Javarecordtipleriyle modellenmesi gerekiyor. - Hizmet Reddi (DoS) ve Tamsayı Taşması Koruması: Zip Bomb, XML varlık genişlemesi (XXE) ve bellek ayırma hesaplamalarındaki tamsayı taşmalarına (integer overflow) karşı
Math.addExact()veMath.multiplyExact()kontrolleri standartlaştırılıyor.
3. Spring Boot’ta jOOQ ve Tip Güvenli SQL: Lukas Eder ile ‘Data Geekery’ Analizi
Spring resmi blogunda (Spring.io) Josh Long'un sunduğu A Bootiful Podcast programına konuk olan jOOQ yaratıcısı Lukas Eder, modern kurumsal Java uygulamalarında ilişkisel veritabanlarıyla (PostgreSQL, DuckDB, ClickHouse, CockroachDB) çalışırken karşılaşılan mimari darboğazları değerlendirdi.
Oturumda öne çıkan en kritik mühendislik tezi, karmaşık okuma ve analitik sorgularda ORM (Hibernate/JPA) katmanının yarattığı N+1 sorgu problemi ve çalışma zamanı (runtime) HQL/JPQL ayrıştırma maliyeti yerine SQL-öncelikli (SQL-first) derleme zamanı tip güvenliğinin kullanılmasıdır:
- jOOQ
MULTISETve İç İçe Koleksiyonlar (Nested Collections): Geleneksel ORM'lerde bir ana kayıt ve ona bağlı birden fazla alt listeyi çekerken oluşan kartezyen çarpım (Cartesian product) patlaması veya çoklu sorgu yükü, jOOQ'un standart SQLMULTISEToperatörüyle tek bir veritabanı sorgusunda çözülür. - Java
recordile Doğrudan Eşleme (Ad-Hoc Type-Safe Mapping): Veritabanı şemasından üretilen jOOQ meta-verisi,Records.mapping(OrderSummaryDTO::new)aracılığıyla yansıma (reflection) kullanmadan doğrudan değişmez Javarecordnesnelerine dönüştürülür.
| Mimari Katman / Özellik | Eski / Geleneksel Java Yaklaşımı | Modern JDK 27 & Spring Boot + jOOQ Yaklaşımı |
|---|---|---|
| Konteyner Varsayılan GC | Küçük konteynerlerde Serial GC geri dönüşü | JEP 523 ile her ortamda evrensel G1 GC |
G1 Yığın Oranları (Min/MaxHeapFreeRatio) |
40 / 70 (Full GC sonrası agresif boyut değişimi) |
0 / 100 (CPU oranı tabanlı akıcı sezgisel boyutlandırma) |
| Kısa Ömürlü İş Parçacığı Belleği | Sabit/büyük TLAB nedeniyle genç nesil bellek israfı | JDK-8381834 ile dinamik ve tutumlu TLAB boyutlandırması |
| Çalışma Zamanı Güvenlik Modeli | SecurityManager (Java 24'te tamamen kapatıldı) |
JPMS modülleri, konteyner izolasyonu, JEP 415 ObjectInputFilter |
| İlişkisel Alt Koleksiyon Sorgulama | ORM N+1 sorguları veya Kartezyen çarpım tekrarı |
jOOQ MULTISET + Records.mapping() ile tek sorguda record projeksiyonu |
Mühendislik Uygulaması: Güvenli Doğrulama (TOCTOU / Overflow) ve Spring Boot jOOQ MULTISET Deposu
Aşağıdaki Java referans uygulaması, güncellenen Java Secure Coding Guidelines ilkelerini (savunmacı List.copyOf() kopyalaması, Math.multiplyExact taşma koruması ve JEP 415 ObjectInputFilter) ve Spring Boot + jOOQ MULTISET ile tek sorguda değişmez record projeksiyonu yapan veri erişim katmanını bir arada göstermektedir:
package com.tastutanlabs.enterprise.order;
import org.jooq.DSLContext;
import org.jooq.Records;
import org.springframework.stereotype.Repository;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputFilter;
import java.io.ObjectInputStream;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import static org.jooq.impl.DSL.*;
import static com.tastutanlabs.enterprise.jooq.Tables.ORDERS;
import static com.tastutanlabs.enterprise.jooq.Tables.ORDER_ITEMS;
// 1. Java Secure Coding Guidelines: Değişmez (Immutable) Record ve Savunmacı Kopyalama
public record OrderLineItemView(String sku, int quantity, BigDecimal unitPrice) {
public OrderLineItemView {
Objects.requireNonNull(sku, "SKU boş olamaz");
Objects.requireNonNull(unitPrice, "Birim fiyat boş olamaz");
if (quantity <= 0) {
throw new IllegalArgumentException("Miktar pozitif olmalıdır");
}
// Tamsayı taşması (Integer Overflow) kontrolü
Math.multiplyExact(quantity, 100);
}
}
public record OrderSummaryView(
UUID orderId,
String customerEmail,
Instant createdAt,
List<OrderLineItemView> items
) {
public OrderSummaryView {
Objects.requireNonNull(orderId, "Sipariş kimliği zorunludur");
Objects.requireNonNull(customerEmail, "Müşteri e-postası zorunludur");
Objects.requireNonNull(createdAt, "Oluşturulma zamanı zorunludur");
// TOCTOU zafiyetine karşı savunmacı değişmez kopya
items = List.copyOf(items);
}
}
@Repository
public class SecureOrderJooqRepository {
private final DSLContext dsl;
// JEP 415: Bağlama özgü katı beyaz liste serileştirme filtresi
private static final ObjectInputFilter STRICT_AUDIT_FILTER = ObjectInputFilter.Config.createFilter(
"maxdepth=3;maxarray=64;maxbytes=4096;java.base/*;!*");
public SecureOrderJooqRepository(DSLContext dsl) {
this.dsl = dsl;
}
// 2. jOOQ MULTISET: N+1 sorunu olmadan tek SQL sorgusunda iç içe koleksiyon projeksiyonu
public List<OrderSummaryView> findRecentOrdersWithItems(String tenantId, int limitCount) {
int safeLimit = Math.clamp(limitCount, 1, 100);
return dsl.select(
ORDERS.ID,
ORDERS.CUSTOMER_EMAIL,
ORDERS.CREATED_AT,
multiset(
select(
ORDER_ITEMS.SKU,
ORDER_ITEMS.QUANTITY,
ORDER_ITEMS.UNIT_PRICE
)
.from(ORDER_ITEMS)
.where(ORDER_ITEMS.ORDER_ID.eq(ORDERS.ID))
).convertFrom(r -> r.map(Records.mapping(OrderLineItemView::new)))
)
.from(ORDERS)
.where(ORDERS.TENANT_ID.eq(tenantId))
.orderBy(ORDERS.CREATED_AT.desc())
.limit(safeLimit)
.fetch(Records.mapping(OrderSummaryView::new));
}
// 3. JEP 415 Filtreli Güvenli Okuma Yardımcı Metodu
public Object deserializeTrustedAuditSnapshot(byte[] rawBytes) throws IOException, ClassNotFoundException {
try (var bais = new ByteArrayInputStream(rawBytes);
var ois = new ObjectInputStream(bais)) {
ois.setObjectInputFilter(STRICT_AUDIT_FILTER);
return ois.readObject();
}
}
}
[!TIP]
Üretim Performansı ve JVM Bayrak Önerisi: JDK 27'ye geçiş yapan mikroservislerde özel olarak tanımlanmış eski-XX:MinHeapFreeRatiove-XX:MaxHeapFreeRatioparametreleri kaldırılarak JVM'in yeni0/100varsayılanlarıyla çalışmasına izin verilmelidir. Veri katmanında ise okuma ağırlıklı uç noktalarda JPA varlık grafikleri (@EntityGraph) yerine jOOQMULTISET+Records.mapping()kullanılması hem GC üzerindeki geçici nesne (allocation rate) baskısını düşürür hem de derleme zamanı SQL güvenliği sağlar.
Yazılım mimarisi, mikroservis ekosistemleri ve üretken yapay zeka uygulamaları üzerine çalışıyorum. TastutanLabs çatısı altında geliştirici araçları ve SaaS ürünleri inşa ediyorum.
Bu analizin 6 kartlık görsel özetini Instagram'da inceleyin ve kaydedin
Her gün yazılım mimarisi, Java/JVM ve yapay zeka gelişmelerini kendi başına okunabilen 6 slaytlık Mini-Blog serileri halinde paylaşıyoruz.
Yorumlar (0)
Düşüncelerinizi Paylaşın
Henüz yorum yapılmamış. İlk yorumu siz yapın!
Bu Kategorideki Diğer İncelemeler
OpenJDK ‘Project Detroit’ (FFM ile V8 ve CPython), Spring Boot Yerel ‘Cloud Foundry / kind’ Orkestrasyonu ve Quarkus 4.0 Mimarisi
OpenJDK'nın Foreign Function & Memory (FFM) API üzerinden Google V8 ve CPython çalışma zamanlarını doğrudan JVM sürecine gömen Project Detroit girişimi, Spring Boot uygulamalarında Docker/kind tabanlı yerel Cloud Foundry dağıtımı ve Quarkus 4.0 (Vert.x 5, HTTP/3, Hibernate 8) mimarisi inceleniyor.
JDK 28’de ‘JEP 401 Value Classes’ ve Değişmez Veri Mimarisi, Spring AI 2.1 ‘MessagePart’ Akıl Yürütme Korunumu ve Özel Vektör ‘Upsert’ API’si
OpenJDK 28 erken erişim sürümlerinde 30 çekirdek sınıfı kimliksiz değer nesnesine dönüştüren JEP 401 (Value Classes), çok turlu akıl yürütme imzalarını kayıpsız taşıyan Spring AI 2.1 MessagePart mimarisi ve önceden hesaplanmış float[] vektörleri destekleyen VectorStore.upsert() yetenekleri inceleniyor.