Java Flags i Aikar Flags — jak ustawić JVM dla Minecrafta
Garbage collector, rozmiar heapa, strategie alokacji pamięci — JVM flags decydują o tym, czy serwer będzie płynny, czy będzie się zacinał co kilka minut. Tłumaczymy zestaw Aikara linia po linii.
Konfiguracja Papera i Spigota odpowiada za logikę świata, ale o tym, jak rzeczywiście chodzi serwer, decyduje JVM — maszyna wirtualna Javy. Dobre flagi JVM potrafią obniżyć opóźnienia GC z 200 ms do 30 ms i utrzymać stabilne 20 TPS przez tygodnie. Złe — sprawią, że serwer co kilka minut będzie się zacinał na sekundę.
W tym wpisie tłumaczymy, czym są JVM flags, co robi każda z linijek słynnych Aikar Flags i jak je dostosować do Twojego serwera.
Czym są flagi JVM?
Flagi (parametry) JVM przekazujesz Javie przy uruchomieniu serwera, np.:
java -Xms6G -Xmx6G -XX:+UseG1GC -jar paper.jar --nogui
Każda flaga zaczynająca się od -XX: to opcja zaawansowana. Sterują m.in. doborem garbage collectora, rozmiarem regionów pamięci, częstotliwością czyszczenia heapu i strategią allokacji.
Garbage Collector — serce wydajności
JVM automatycznie zarządza pamięcią. Co jakiś czas „zbiera śmieci" — usuwa obiekty, które nikt już nie używa. Stary ParallelGC robi to w jednej, długiej pauzie. Nowoczesny G1GC rozkłada to na małe porcje. Dla serwera Minecraft G1GC jest dziś standardem.
Bardzo duże heapy (16 GB+) mogą skorzystać z ZGC lub Shenandoah, które dają submilisekundowe pauzy, ale zużywają nieco więcej CPU. Dla większości serwerów do 50 graczy G1GC wystarcza w 100%.
Aikar Flags — domyślny zestaw
Aikar Flags to zestaw stworzony przez głównego dewelopera Papera. Zoptymalizowany pod kątem niewielkich, częstych pauz GC — idealny dla Minecrafta:
java -Xms6G -Xmx6G \
-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 \
-Dusing.aikars.flags=https://mcflags.emc.gs \
-Daikars.new.flags=true \
-jar paper.jar --nogui
Co robią poszczególne flagi?
-Xms / -Xmx
Minimalny i maksymalny rozmiar heapu. Ustaw je na tę samą wartość — JVM nie będzie marnować czasu na powiększanie heapu.
-XX:+UseG1GC
Włącza Garbage-First Collector — domyślny GC dla Javy 9+, ale i tak warto wymusić.
-XX:MaxGCPauseMillis=200
Cel maksymalnej pauzy GC: 200 ms. JVM samodzielnie dobiera rozmiary regionów, by mieścić się w tym limicie.
-XX:+ParallelRefProcEnabled
Włącza równoległe przetwarzanie referencji w GC. Przyspiesza zbieranie weak/soft referencji w dużych światach.
-XX:+DisableExplicitGC
Ignoruje wywołania System.gc() z pluginów. Niektóre źle napisane pluginy wywołują to co kilka minut, powodując długie pauzy.
-XX:+AlwaysPreTouch
Pre-allokuje całą pamięć od razu przy starcie. Daje wyższy cold start time, ale eliminuje opóźnienia podczas pierwszego użycia stron pamięci.
-XX:G1NewSizePercent / G1MaxNewSizePercent
30%/40% to większy young generation niż domyślny. Minecraft tworzy mnóstwo krótko żyjących obiektów (entity, particle), więc warto je tutaj umieścić.
-XX:G1HeapRegionSize=8M
Rozmiar regionu G1. 8 MB to zwykle najlepszy kompromis dla heapów 4–16 GB.
-XX:InitiatingHeapOccupancyPercent=15
GC startuje cykl mixed, gdy zajętych jest 15% heapu. Niska wartość = częste, ale krótkie pauzy.
-XX:MaxTenuringThreshold=1
Mocno ogranicza promocję obiektów do old generation. Większość entity Minecrafta i tak ginie w młodym pokoleniu.
Ile RAM-u dać Javie?
Reguła praktyczna: 50–70% pamięci VPS-a, reszta dla systemu, MySQL i innych usług. Przykłady:
- VPS 4 GB →
-Xms3G -Xmx3G - VPS 8 GB →
-Xms6G -Xmx6G - VPS 16 GB →
-Xms12G -Xmx12G - VPS 32 GB →
-Xms24G -Xmx24G
Więcej RAM-u nie zawsze oznacza więcej wydajności. Heap powyżej 16 GB zwykle wymaga już ZGC, by uniknąć długich pauz.
Kiedy ZGC zamiast G1GC?
Jeśli masz heap 16 GB+ i widzisz w sparku regularne pauzy 100+ ms, warto przetestować ZGC:
java -Xms16G -Xmx16G \
-XX:+UseZGC \
-XX:+ZGenerational \
-XX:+AlwaysPreTouch \
-jar paper.jar --nogui
ZGC daje pauzy <1 ms niemal niezależnie od rozmiaru heapu. Wymaga jednak więcej CPU i wyłączenia części flag G1.
Czego unikać
- Stare flagi z lat 2014–2017 —
UseConcMarkSweepGCjest usunięty z Java 14+. - Bardzo wysokie
MaxGCPauseMillis(1000+) — to nie jest „sztywny limit", tylko wskazówka. Daje GC zbyt dużo swobody. - Heap równy całemu RAM-owi VPS-a — system zaraz uderzy w swap.
- Niejednakowe
-Xmsi-Xmx— JVM marnuje czas na resize heapu.
Jak sprawdzić, czy flagi działają?
Po starcie z nowymi flagami:
- Włącz
/spark health— pokaże procent czasu spędzonego w GC. - Obserwuj
/tpsprzez 30 minut przy normalnym ruchu. - Sprawdź
logs/latest.logpod kątemGC overhead limit exceeded.
Zdrowy serwer ma <5% czasu w GC i 19.9–20 TPS przy podstawowym obciążeniu.
Podsumowanie
JVM flags wyglądają groźnie, ale w praktyce 95% serwerów potrzebuje tylko Aikar Flags z odpowiednim -Xms/-Xmx. Reszta to fine-tuning, który ma sens dopiero po profilingu sparkiem.
Jeśli dopiero zaczynasz: skopiuj zestaw Aikara, ustaw RAM na ~60% VPS, włącz spark i nie kombinuj z innymi flagami przez pierwsze 2 tygodnie.