I've been hosting a minecraft server for about 2 months now, and as every fabric server owner I like optimization, and a lot of it.
For servers I have tried the Shenandoah, C4, ZGC, Shenandoah IU, Shenandoah Generational and the G1 garbage collectors mainly serverside, but I did some clientside testing too.
All of them except G1GC sucked, and I've determined that by normal usage and a test of mine.
The test I've tried:
- Spawn about 20 players with carpet's
/player
command, - Then, run
/spreadplayers 0 0 1000 10000 false @a
to spread players in a 10k block radius around the world
With Shenandoah, Shenandoah Generational and ZGC Minecraft spread the players, and the tps dropped to 10, and went down until 1.
With G1 it dropped to 17-18 for about half a minute then stabilized at 20.
The test might be inaccurate and inconsistent in some cases, don't take it too seriously, it's just an example
ZGC and Shenandoah/Shenandoah Generational took 2 seconds to GC every time.
G1 took 10-60ms for every GC. (both were measured with spark gcmonitor)
Intel Xeon E5-2698 v4 with 16 threads (because I was using a QEMU/KVM VM)
16GB RAM
350GB HDD storage for server (irrelevant)
none
From a simple spark healthreport, here are the results I get with:
Average MSPT: 28
TPS: 20
CPU usage: 4-5%
Average MSPT: 20-30 (apparently MSPT isn't locked to TPS, as ishland from the RelativityMC server told me)
TPS: 1.96
CPU usage: 55-60% because of extremely frequent and slow GCs
I'm doing these tests in my main env, which is the server for the SuperCharged modpack.
Modlist: https://webducky.cf/kat/modlist.txt
For G1GC I have used my flags which are Aikar's stripped of G1 heap settings which worsen performance on some devices + G1 tweaks itself anyway.
On ZGC I used -XX:ConcGCThreads=4
however performance is the same without it
On ShenandoahGC I used ShenandoahGC only and hilltty's flags, I have also tested Shenandoah Generational, all performed about the same.
Do note that I'm not saying ShenandoahGC or ZGC are bad, but on most setups they might not work well, while G1 is almost universal.
Fast and prevents memory leaks.
I provide an env var for jemalloc with these flags, which enables the background thread it runs on and also improves speed
Might be faster than Jemalloc, however might have more memory leaks, no configuration env var
- First of all, you'd want to install the Corretto or Zulu JDK or JRE, and make your Minecraft launcher of choice use the JDK/JRE you installed. Downloads for Zulu (DO NOT USE PRIME): https://www.azul.com/downloads/ and downloads for Corretto: https://aws.amazon.com/corretto/
- (For Linux only) Also, install jemalloc and gamemoderun (feral-gamemode), go to launcher options and set wrapper command to
env LD_PRELOAD=/usr/lib/libjemalloc.so MALLOC_CONF=abort_conf:true,background_thread:true,narenas:4,dirty_decay_ms:1000,muzzy_decay_ms:1000 gamemoderun
2.1. Change the 4 innarenas:4
to the amount of threads on your machine - Then, you'd want to set the allowed memory of MC to 4-6GB if you only have 8GB of RAM on host, and 8-12GB if you have 16GB of RAM on host (make sure to NOT give Minecraft more than 12GB of RAM on G1 heaps).
- Afterwards, set your Java flags to
-XX:+PerfDisableSharedMem -XX:+UseStringDeduplication
Note: make sure to not run any heavy programs besides MC when playing, e.g. another game
- Install the IBM Semeru runtime, which includes OpenJ9 here https://developer.ibm.com/languages/java/semeru-runtimes/downloads/
- Follow step 2 (if on Linux) and 3 of the guide for Singleplayer (about 4GB is recommended, more than that helps only a bit)
- Set Java flags to
-Xshareclasses:bootClassesOnly
It's fine to run other programs other than MC, just make sure it's not a lot and it isn't heavy programs
OpenJ9 has extremely low RAM usage, though if you get any issues report them to OpenJ9, not the mod/plugin creator
- Follow step 1 of client, Singleplayer
- Then, step 2 (if on Linux), and step 3 but instead of dragging a slider to set RAM, take the flags from step 4 and put
-Xms12G -Xmx12G
before them (replace 12 with the amount of RAM you can give), also, make sure to NOT give over 12GB of RAM because it will make performance worse.
Example launch command:
LD_PRELOAD=/usr/lib/libjemalloc.so MALLOC_CONF=abort_conf:true,background_thread:true,narenas:4,dirty_decay_ms:1000,muzzy_decay_ms:1000 java -Xms12G -Xmx12G -XX:+PerfDisableSharedMem -XX:+UseStringDeduplication -jar fabric.jar
This is mainly only useful after you got mods like Lithium, Sodium (client only), C2ME (in alpha, also only useful on 8+ threads), FerriteCore, Starlight and others (I recommend going to https://modrinth.com and using the optimization filter)
They are outdated, and the G1 garbage collector finds the best options by itself, so the G1 heap options might make performance worse, however the rest of the flags is useful and I include them.
In some cases, ShenandoahGC or ZGC can perform way worse, as shown by my tests, however they might work better in some cases
Because Singleplayer has to run an internal server.
Because they won't work on every setup ranging from a pentium 2 to a ryzen 5950x.
Always make sure that you're able to revert changes, and make backups.
Thanks to Transformer from the CaffeineMC discord for the MALLOC_CONF env var, also thanks to ishland from RelativityMC for recommending OpenJ9