Minecraft sunucusunda garbage collector (çöp toplayıcı) ayarları, TPS’i kâğıt üzerinde değil oyuncu tarafında düzelten birkaç ayardan biridir. Java, artık kullanılmayan nesneleri sizin yerinize temizler; bunu yaparken de zaman zaman uygulamayı tamamen durdurur. Sunucunun tick bütçesi 50 milisaniyedir. Bu bütçenin ortasına düşen 300 milisaniyelik bir duraklama, tek başına altı tick’lik gecikme üretir ve oyuncular bunu “sunucu bir an takıldı” diye hisseder.
Bu sayfada GC’nin neden lag yarattığını, Java 25’te hangi çöp toplayıcının varsayılan olduğunu, G1 ile ZGC arasındaki gerçek farkları, heap büyüklüğüne göre hangisini seçmeniz gerektiğini ve duraklamaları nasıl ölçüp okuyacağınızı bulacaksınız. Anlatılanlar Paper, Purpur, Spigot, Forge ve Fabric sunucularının hepsinde aynı şekilde geçerlidir; çünkü bayraklar sunucu yazılımına değil doğrudan JVM’e verilir.
Çöp toplayıcı nedir ve neden lag yaratır?#
Java’da nesneleri elle silmezsiniz. Bir nesneye artık hiçbir yerden erişilemiyorsa çöp toplayıcı onu bulur ve kapladığı alanı geri kazandırır. Bu iş sessizce yapılabilseydi kimse GC ayarı konuşmazdı. Ne var ki toplayıcının bazı aşamaları, nesne grafiğinin tutarlı kalması için uygulamanın durmasını gerektirir — literatürde buna “stop-the-world duraklaması” denir.
Minecraft bu iş için zor bir müşteridir. Her tick’te konum vektörleri, paket nesneleri, entity durum kopyaları, chunk anahtarları üretilir ve neredeyse hepsi milisaniyeler içinde çöpe döner. Yani heap’e sürekli, yüksek hızda ve çok kısa ömürlü nesne akar. İyi ayarlanmış bir toplayıcı bu akışı küçük ve sık turlarla temizler; kötü ayarlanmış bir toplayıcı çöpü biriktirir, sonra hepsini tek seferde temizlemeye kalkar ve sunucuyu yarım saniye durdurur.
Modern toplayıcıların hepsi aynı gözlemin üstüne kurulur: nesnelerin büyük çoğunluğu doğduktan hemen sonra ölür. Bu yüzden heap iki kuşağa ayrılır. Yeni nesneler genç kuşakta doğar; oradaki temizlik ucuzdur, çünkü hayatta kalan azdır. Birkaç turu atlatan nesneler eski kuşağa terfi eder ve orada temizlik pahalıdır. Minecraft ayarlarının çoğu tek bir amaca hizmet eder: nesneleri eski kuşağa terfi ettirmeden genç kuşakta öldürmek. Çünkü eski kuşak şiştiğinde, er ya da geç saniyeler süren bir tam toplama kapıyı çalar.
Java 25’te varsayılan çöp toplayıcı hangisi?#
Cevap net: G1. Java 25’te JEP 523 ile G1, kısıtlı ortamlar dâhil tüm ortamlarda JVM’in genel varsayılan çöp toplayıcısı olarak tanımlandı. Hiçbir GC bayrağı vermeden java -jar paper.jar yazarsanız sunucunuz G1GC ile açılır.
Burada 2026’nın en yaygın yanlış bilgisine değinelim. 26.1 sürüm notlarında geçen “garbage collection has been changed from G1GC to ZGC for compatible computers” satırı, Minecraft Launcher’ın oyun istemcisine verdiği JVM varsayılanını anlatır. Aynı notlardaki “oyun artık varsayılan 4 GB RAM ayırıyor” maddesi de istemci tahsisidir. Sunucu jar’ının launcher’ı yoktur; sunucunun çöp toplayıcısını tamamen operatörün verdiği bayraklar belirler.
-XX:+UseZGC -XX:+ZGenerational kombinasyonunu da kopyalamayın: JEP 490 ile ZGC’nin non-generational modu kaldırıldı, -XX:+ZGenerational Java 25’te obsolete’tir ve yalnızca uyarı basar. Doğru kullanım tek başına -XX:+UseZGC.G1 ve ZGC karşılaştırması#
İki toplayıcı farklı şeyler için optimize edilmiştir. G1 verimi (throughput) ile duraklama arasında denge kurar; ZGC ise duraklamayı ne pahasına olursa olsun kısa tutmayı hedefler.
| Ölçüt | G1GC | ZGC |
|---|---|---|
| Java 25’te durumu | Genel varsayılan | Açıkça -XX:+UseZGC ile seçilir |
| Tipik duraklama | 10-200 ms (ayara bağlı) | Çoğunlukla 1 ms altı |
| Duraklamanın heap ile ilişkisi | Heap büyüdükçe duraklama uzama eğiliminde | Heap büyüklüğünden büyük ölçüde bağımsız |
| CPU maliyeti | Düşük | Kabaca %10-15 daha fazla |
| Heap dışı bellek | Düşük | Birkaç puan daha yüksek |
| İnce ayar imkânı | Çok geniş (Aikar’s Flags) | Sınırlı, bilinçli olarak az bayraklı |
| Topluluk deneyimi | Yıllardır her sunucu tipinde test edildi | Görece yeni, ölçüm gerektirir |
| Uygun heap aralığı | 8-12 GB, isterse daha üstü | 16 GB ve üzeri, ağır modlu sunucular |
Tablodaki en önemli satır CPU maliyetidir. ZGC duraklamayı yok etmiyor, işin çoğunu arka plana taşıyor; bu iş için ek çekirdek zamanı harcanıyor. Ana tick döngüsü zaten tek çekirdeğe sıkışmış bir sunucuda boşta çekirdek varsa bu takas kârlıdır. Çekirdek sıkışıksa ZGC net kayıp yazdırabilir.
Heap büyüklüğüne göre doğru seçim#
Karar tablosu aslında tek satıra sığar ama gerekçesiyle yazalım:
| Paket RAM | Heap (-Xms / -Xmx) | Önerilen GC | Gerekçe |
|---|---|---|---|
| 8 GB | -Xms6G -Xmx6G | G1GC + Aikar’s Flags | Bu heap’te ZGC’nin CPU maliyeti kazancını yer |
| 12 GB | -Xms10G -Xmx10G | G1GC + Aikar’s Flags | Setin en çok test edildiği aralık; duraklamalar zaten kısa |
| 16 GB | -Xms14G -Xmx14G | G1GC (büyük heap varyantı) veya ZGC | Sınır bölge. İkisini de ölçün, sunucunuza göre karar verin |
| 32 GB | -Xms28G -Xmx28G | ZGC değerlendirilir | Büyük heap’te G1’in karışık turları uzar; ZGC burada avantajlı |
Her satırda -Xms ve -Xmx eşit ve toplam bellekten 2 GB pay bırakılmış durumda; bu pay işletim sistemi, JVM’in metaspace alanı, Netty tamponları ve disk önbelleği içindir. Boyutlandırmanın ayrıntısı RAM ayarları sayfasında. Modlu sunucularda tablo bir kademe yukarı kayar; modlu sunucu RAM rehberi paket büyüklüğüne göre gerçek rakamları veriyor.
G1GC için başlatma satırı#
G1 tarafında iş, Aikar’s Flags’i doğru heap değeriyle kullanmaktan ibarettir. 12 GB’lık bir paket için:
java -Xms10G -Xmx10G --add-modules=jdk.incubator.vector -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1HeapRegionSize=8M -XX:G1ReservePercent=20 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1 -jar paper.jar --nogui
Bayrakların tek tek ne yaptığını Aikar’s Flags sayfasında tablo hâlinde açıkladık. Heap 12 GB’ı aşarsa beş bayrağın değeri değişir; o değişiklikler de aynı sayfada.
ZGC için başlatma satırı#
ZGC’nin felsefesi az bayraktır. G1’e ait hiçbir ayarı taşımayın:
java -Xms28G -Xmx28G -XX:+UseZGC -XX:+UseCompactObjectHeaders -XX:+UseStringDeduplication -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+PerfDisableSharedMem -jar paper.jar --nogui
Buradaki -XX:+UseCompactObjectHeaders, JEP 519 ile Java 25’te deneysel olmaktan çıkıp kararlı özelliğe terfi etti ve her nesnenin başlığını 12 bayttan 8 bayta indirir. Modlu bir sunucuda heap’te milyonlarca nesne olduğu için bu tek bayrak gözle görülür bellek tasarrufu sağlar. -XX:+UseStringDeduplication ise tekrar eden karakter dizilerini birleştirir; NBT ve registry string’i bol olan modlu paketlerde işe yarar.
-XX:+UseZGC ile birlikte G1NewSizePercent, G1HeapRegionSize veya MaxGCPauseMillis yazarsanız bayraklar ya yok sayılır ya da JVM hiç açılmaz. Forumlardaki “sunucu açılmıyor” vakalarının azımsanmayacak bir kısmı bu karışımdan çıkıyor.GC günlüğünü açmak ve okumak#
GC ayarı tahminle yapılmaz, ölçülerek yapılır. Başlatma komutuna aşağıdaki bayrağı ekleyin; günlükler beş dosyada döner, disk şişmez:
-Xlog:gc*:file=logs/gc.log:time,uptime:filecount=5,filesize=10M
Dosyada göreceğiniz satırlar şuna benzer. Sondaki milisaniye değeri duraklama süresidir ve gerçekten önemsediğiniz tek sayıdır:
[2026-08-25T14:02:11.482+0300][412.907s] GC(184) Pause Young (Normal) (G1 Evacuation Pause) 5820M->3910M(10240M) 24.116ms
[2026-08-25T14:02:39.104+0300][440.529s] GC(185) Pause Young (Concurrent Start) (G1 Humongous Allocation) 6144M->4402M(10240M) 31.884ms
[2026-08-25T14:02:41.550+0300][442.975s] GC(186) Pause Remark 4402M->4398M(10240M) 6.201ms
[2026-08-25T14:02:47.870+0300][449.295s] GC(188) Pause Full (Allocation Failure) 9987M->9214M(10240M) 2874.553ms
Satırları okumak sandığınızdan kolay. 5820M->3910M(10240M) ifadesi “heap 5820 MB’tan 3910 MB’a düştü, toplam kapasite 10240 MB” demektir. Pause Young satırlarının 10-40 ms bandında olması normaldir. Asıl aradığınız şey son satırdaki gibi bir Pause Full kaydıdır: 2,8 saniye süren bir tam toplama, sunucuyu neredeyse üç saniye durdurmuş demektir. Bir de temizlik sonrası heap’in inmediğine bakın — örnekteki Full GC 9987 MB’tan yalnızca 9214 MB’a inmiş, yani bellek gerçekten dolu.
grep -c "Pause Full" logs/gc.log
grep "Pause Full" logs/gc.log | tail -20
awk '{print $NF}' logs/gc.log | grep "ms$" | sort -rn | head -10
Windows tarafında aynı taramayı Select-String -Path .\logs\gc.log -Pattern "Pause Full" ile yaparsınız. Sonuç boşsa tebrikler, GC tarafında bir sorununuz yok; darboğazı başka yerde aramanız gerekiyor.
Duraklama sürelerini oyun içinden ölçmek#
Günlük dosyası tarihsel kayıt verir, spark ise anlık tablo. Sunucuya spark kurduktan sonra üç komut yeter:
/spark gc
/spark health --memory
/spark heapsummary --run-gc-before
/spark gc son GC turlarının süresini ve sıklığını özetler; /spark health --memory heap kullanımını ve toplayıcı davranışını tek ekranda gösterir; /spark heapsummary ise hangi sınıfın kaç megabayt tuttuğunu listeler — “RAM’i hangi eklenti yiyor” sorusunun tahminsiz cevabı budur. Raporları yorumlamayı spark ve timings analizi sayfasında anlattık.
Ayarın gerçekten uygulandığını doğrulamak için de JVM’e doğrudan sorun:
jcmd $(pgrep -f paper.jar) VM.flags
jcmd $(pgrep -f paper.jar) GC.heap_info
İlk komut JVM’in gerçekte hangi bayraklarla açıldığını basar — başlatma dosyanıza yazdığınızı sandığınız bayrağın oraya ulaşmadığını en hızlı böyle görürsünüz. İkincisi anlık heap dağılımını, yani genç ve eski kuşağın doluluğunu verir. Windows tarafında süreç kimliğini jcmd -l ile bulup aynı alt komutları çalıştırırsınız. Bu iki çıktı, “ayarı yaptım ama bir şey değişmedi” şikayetlerinin yarısını daha ilk bakışta çözer: bayrak çoğu zaman -jar ifadesinden sonraya yazılmış olduğu için JVM’e hiç ulaşmamıştır.
Diğer çöp toplayıcılar: kullanmalı mı?#
JVM’de G1 ve ZGC dışında toplayıcılar da var, ama Minecraft sunucusu için hikâyeleri kısa:
- SerialGC — tek iş parçacığıyla çalışır, küçük heap’ler için tasarlandı. 8 GB ve üzeri heap’te duraklamaları saniyelere çıkarır. Kullanmayın.
- ParallelGC — verimi yüksektir ama duraklama hedefi yoktur. Toplu iş uygulamaları için iyidir; oyuncuların gerçek zamanlı beklediği bir sunucu için değil.
- Shenandoah — ZGC’ye benzer düşük duraklama hedefiyle çalışır. Teknik olarak kullanılabilir, ancak Minecraft tarafında topluluk ölçümü ZGC kadar birikmiş değil. Üretim sunucusunda maceraya girmeyin.
- CMS — modern JVM’den tamamen kaldırıldı. Eski rehberlerdeki
-XX:+UseConcMarkSweepGCbayrağını yazarsanız sunucu hiç açılmaz.
Yani pratikte tercih iki seçenek arasındadır ve bu iyi bir haber: karşılaştırmanız gereken yapılandırma sayısı iki. Eski bir sunucuyu 26.2’ye taşırken başlatma satırını sıfırdan yazın; sürüm yükseltme rehberi geçişte gözden kaçan noktaları listeliyor.
GC ayarlarında sık yapılan hatalar#
Heap’i fiziksel bellekten büyük vermek#
16 GB’lık makinede -Xmx16G yazmak klasik hatadır. JVM’in heap dışı ihtiyacı kalmadığı için sistem takas alanına düşer ve duraklamalar saniyelere çıkar. Doğrusu -Xmx14G’dir. Bu tuzağın belirtilerini OutOfMemoryError sayfasında topladık.
Heap büyütmeyi tek çözüm sanmak#
Bellek sızdıran bir eklenti varsa büyütülen heap yalnızca Full GC’nin gelmesini geciktirir. Bir hafta sonra aynı çöküşü daha büyük bir heap’le yaşarsınız. GC log’unda temizlik sonrası taban seviyesi sürekli yükseliyorsa sızıntı vardır; heap değil eklenti değişmelidir.
Rastgele bayrak yığmak#
Farklı rehberlerden toplanmış bayrakları arka arkaya eklemek çelişkili yapılandırma üretir. Bir GC seçin, o GC’nin setiyle devam edin, sonra tek tek ölçün.
GC’yi CPU sorununun üstünü örtmek için kullanmak#
Çöp toplayıcı ayarı, entity yığılmasını, hopper zincirlerini veya senkron çalışan bir eklentiyi düzeltmez. Bunlar için optimizasyon rehberindeki adımlar ve paper.yml ayarları gerekir. Ayrıca ana tick döngüsü tek çekirdekte çalıştığı için saat hızı yüksek bir AMD Ryzen 9 ve NVMe SSD, hiçbir bayrağın telafi edemeyeceği bir temeldir; bu profildeki hazır sistemleri Minecraft sunucu paketleri tarafında bulabilirsiniz.
Gerekli indirmeler#
26.1 ve sonrası Java 25 ister. Java 26 çıktı ama LTS değil, sunucu tarafında Java 25 LTS’te kalın. Sürüm eşleşmesinin tamamı hangi Java sürümü gerekir sayfasında.
Bağlantılar resmî kaynaklara gider. Üçüncü taraf sitelerden jar veya JDK indirmeyin.
Özetle#
Çöp toplayıcı, Minecraft sunucusunda lag üretme gücü olan az sayıdaki JVM ayarından biridir ve mesele temizliğin kendisi değil, temizlik sırasındaki duraklamadır. Java 25’te varsayılan toplayıcı G1’dir; bayrak vermeden çalışan bir 26.2 sunucusu ZGC değil G1GC kullanır, çünkü 26.1’deki geçiş istemci JVM’ini ilgilendirir. 8-12 GB heap’te G1GC ve Aikar’s Flags kalın; 16 GB üzeri heap veya ağır modlu bir sunucuda ZGC’yi ölçerek değerlendirin, -XX:+ZGenerational yazmayın ve iki setin bayraklarını asla karıştırmayın.
Son olarak, ayarı yaptıktan sonra ölçün. -Xlog:gc* günlüğünü açın, Pause Full satırlarını sayın, spark ile duraklama geçmişine bakın. Herşey normalse ve hâlâ takılma yaşıyorsanız sorun çöp toplayıcıda değildir — o zaman entity, chunk ve eklenti tarafına geçmenin vakti gelmiş demektir. Elinizdeki GC günlüğünü yorumlamakta zorlanırsanız kaydı ekleyerek destek talebi açabilirsiniz.