This is the detailed Minecraft Java Arguments guide and is a part of the overarching Minecraft Performance Guide
This repository serves the purpose of having an updated list of Java Arguments for Minecraft. Testing has been conducted for both Modded Minecraft and Vanilla Minecraft.
This guide will be a more in-depth version of the general guide in the Minecraft Performance Guide.
This guide contains information about different types of Java Runtime Environments's (JREs) and the Java Virtual Machine (JVM) arguments for each of them.
It is possible depending on the system for these arguments to only minimally provide Ticks Per Second (TPS) and Frames Per Second (FPS) gains.
The purpose of these tweaks are to reduce stutters on the client as a result of garbage collection and other JVM issues which can be fixed through JVM arguments, however, significant server stutters will also be reduced as a result of these arguments if they are in-use on the server.
It is also possible as a result of the usage of these arguments to increase Random Access Memory (RAM) and Central Processing Unit (CPU) usage, which is not necessarily a negative aspect.
Second Disclaimer:
This guide mentions NeoForge, NeoForge is intended to fully replace Forge. The full development team of Forge, minus 1 person forked Forge and created NeoForge. For future developmental purposes, NeoForge will be the new modloader.
Since the purpose of this is not to necessarily fix TPS or FPS issues caused by mods I would recommend looking at these two mods in order to help diagnose your lag issues:
Spark - Curseforge >=1.12.2
Spark - Modrinth >=1.12.2
or
(Observable is an updated version of LagGoggles)
Observable - Curseforge >=1.16.5
Observable - Modrinth >=1.16.5
or
LagGoggles - Curseforge 1.10.2, 1.12.2
I also highly recommend pregenerating your world as this will greatly help with memory usage.
Chunk-Pregenerator - Curseforge >=1.4.6
or
Chunky - Curseforge >=1.16.5
Chunky - Modrinth >=1.16.5
Note: All mods above have Forge/Fabric versions, most have versions for NeoForge now
| Minecraft Version | Java Version |
|---|---|
| >= 1.20.5 | 21 |
| >= 1.19.2 | 17, 19, 21. Depending on the modpack it may be beneficial to use Java 17 over Java 19 or 21. Java 21 has significant improvements over 20 is why 20 is not recommended and should be able to be dropped in place in any instance Java 20 can be used. |
| > 1.16.5 | 17 |
| = 1.16.5 | It is recommended to use Java 17 for Minecraft 1.16.5, however, in certain cases this may break some things, if you notice it is unplayable I recommend switching to Java 8. Although, some people may recommend going with Java 11/15/16 which should work with 1.16.5 it should have a better performance boost defaulting to Java 8. |
| < 1.16.5 | 8. In some instances you may be able to use Java 17 such as GTNH. |
| < 1.7.10 | You may need to use Java 7, for example 1.6.4 |
Depending on your launcher you may be asked to use a different Java version. Curseforge and Prism will ask you to use Java 8 when you are on Minecraft 1.16.X, however, most 1.16.5 mods are compatible with Java 17.
There are many different Java Runtime's and people who own these Runtimes. There are quite a few which are almost identical, as a result of this quite a few different ones have been skipped as they do not provide any substantial differences between them which would result in a meaningful difference.
The most popular companies/people behind the different Runtimes are: Adoptium, Amazon, Azul, IBM, Intel, Microsoft, Oracle, and Red Hat.
The most notable differences between these different Java Runtimes are as follows:
-
Oracle GraalVM - Comes with a more aggressive Java compiler and ZGC - This is currently the most recommended JVE for performance
-
Intel's Clear Linux OpenJDK - Uses the same code as many other OpenJDKs which makes it highly compatible. The build process itself and the dependencies are optimized for newer CPUs. You can get it from Clear Linux's repositories via
swupd, from Distrobox, or from Docker. It is important to note that in order to use this you must currently use the Java 17 release, and that Java 18 reverts some of the performance enhancements. -
Azul's Prime OpenJDK - Very fast since it hooks into LLVM, but its currently incompatible with most mods and is linux-only. You can get it from Azul Prime's docs
-
Red Hat Java 8 - Has the Shenandoah garbage collector. It's gated behind a free email signup at Redhat
-
IBM's OpenJ9 - Substantially slower in Minecraft, and uses totally different flags than any other Java build, but it does consume less memory than OpenJDK-based runtimes. See Frequently Asked Questions, and this Gist for low memory consumption flags.
If you dont know what to pick, I recommend GraalVM for the newest version of Minecraft using Java 17, or GraalVM EE using Java 8 (see below) or the latest Adoptium Java 17 JRE
Couleur maintains a good running list of JREs (Note: This may be a little outdated now)
It is important to note that the launcher you use may influence the behavior of how you input your java arguments/flags.
It is recommended to not use Curseforge's Modded Minecraft launcher, if you choose to do so, know you need to set your Java
/bin/javaw.exepath at every startup of Minecraft, not Curseforge. The option for changing the Java version in Curseforge is for installing the Forge modloader and not the actual Java version Minecraft will run with (yes, Curseforge made it sound confusing).
I do not currently recommend Modrinth's launcher, however, I have included it anyways (they do not have a direct link on how to input your java arguments/flags)
Depending on your launcher, you may also have to edit the available copy-paste ready flags. Typically, the only thing you need to modify is removing the -Xmx8G -Xms8G at the start. This is because the launcher already has a way to set the memory allocation and you should use that instead.
Minimum and maximum (-Xms and -Xmx) memory should be set to the same value, as explained
One exception: if you are on a low-memory system, and Minecraft takes up almost all your RAM, set your minimum memory below your maximum memory to conserve as much as possible.
Sizes are set in megabytes (-Xms4096M) or gigabytes (-Xmx8G)
Allocating too much memory can break garbage collection or just slow Minecraft down, even if you have plenty to spare.
Allocating too little can also slow down or break the game.
Keep a close eye on the Window's Task manager (or your DE's system monitor) as Minecraft is running, and allocate only as much as it needs (which is usually less than 8GB but can be more for larger modpacks! As a client I recommend <16GB in most situations). /sparkc gcmonitor will tell you if your allocation is too high (the pauses will be too long) or too low (frequent garbage collection with a low memory warning in the notification).
You should also only ever allocate >=32GB of ram when you are on a server. Once you enable 32GB of memory you disable compressed OOPs which will impact performance. It is possible to enable OOPs when using >=32GB, however, it will still negatively impact performance
Many people are still under the belief that you should only use 4-8GB of memory, this is not true and has not been true for a very long time. Most modded packs perform best when using 6-16GB of memory client-side. It is also possible, depending on the version and if there are mods, and how many mods, that you need less or even more than this 6-16GB range. I highly recommend testing this yourself and seeing what performs best as there is a large amount of variables to consider.
Note: I highly recommend hosting both vanilla and modded on a server. Hosting on a server will reduce client stress and will increase overall performance. If you are looking for a free option, Oracle offers a permanent always free-tier (which should not be confused with the free trial) you can find a good guide how to setup an Oracle server with this Youtube video
These flags run with any Java 11+ Environment. They work on both servers and clients:
(You must add garbage collection flags to these java arguments. These arguments only act as a base to append further flags to.)
-XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3
These flags run with any Java 8 Environment, they work on both servers and clients:
These flags will work with OpenJDK8, along with Shenandoh GC, or G1GC:
-XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+ParallelRefProcEnabled -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:+PerfDisableSharedMem -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -XX:MaxInlineLevel=15 -XX:MaxVectorSize=32 -XX:+UseCompressedOops -XX:ThreadPriorityPolicy=1 -XX:+UseNUMA -XX:+UseDynamicNumberOfGCThreads -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=350M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseFPUForSpilling -Dgraal.CompilerConfiguration=community
x86 Java 8 users (aka most Java 8 users) can add these additional arguments:
-XX:+UseXMMForArrayCopy
Garbage collection flags must be added to Minecraft servers and clients, as the default pauses/stutters to stop and collect garbage manifest on the client and lag on servers. Use the /sparkc gcmonitor command with the Spark mod to observe stutters in-game. Any old generation pauses are bad, and young generation G1GC collections should be infrequent, but short enough to be not noticeable.
Pick one set of flags. I recommend Shenandoah on clients, ZGC on powerful Java 17 servers, and G1GC on Graal or on servers/clients with less RAM and fewer cores:
ZGC is great for high memory and high core count servers. It has no server throughput hit which can be significantly measured, and does not stutter. However, it requires more RAM and more cores than most other garbage collectors.
ZGC may cause a significant client FPS hit. See the "ZGC" benchmarks in the benchmarks folder. It's not available in Java 8, and much less performant in Java 11 than in Java 17.
-XX:+UseZGC -XX:AllocatePrefetchStyle=1 -XX:-ZProactive enables it, but allocate more RAM and more ConcGCThreads than you normally would for other garbage collectors.
Note: ZGC does not like AllocatePrefetchStyle=3, hence setting it to 1 overrides the previous entry which has already been done in these flags for you.
If we were to use Java >8 with only ZGC it would look like this
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseZGC -XX:AllocatePrefetchStyle=1 -XX:-ZProactive
Shenandoah performs well on clients, but may kill server throughput.
Enable it with -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGuaranteedGCInterval=1000000 -XX:AllocatePrefetchStyle=1
See more tuning options here. The "herustic" and "mode" options don't change much for me (except for "compact," which you should not use). Like ZGC, Shenandoah does not like AllocatePrefetchStyle=3.
Note: Shenandoah is not in Java 8. It's also not currently in any Oracle Java builds. If you are a Java 8 user, you must use Red Hat OpenJDK to use Shenandoah
Download sources
-
Adoptium Temurin: https://adoptium.net/temurin/releases/?version=17&os=any
-
Oracle OpenJDK: https://wiki.openjdk.org/display/shenandoah/Main
If we were to use Java >8 with only Shenandoah it would look like this
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGuaranteedGCInterval=1000000 -XX:AllocatePrefetchStyle=1
G1GC is the default garbage collector for all JREs, (and was previously the only available garbage collector for GraalVM). and is the only available garbage collector for GraalVM users.
Aikar's famous Minecraft server G1GC arguments run great on clients
There are two caveats: they effectively clamp the MaxGCPauseMillis parameter by setting G1NewSizePercent so high, producing long stutters on some clients, and they collect oldgen garbage too aggressively (as the client produces far less than a populated server).
These flags are similar to the aikar flags, but with shorter, more frequent pauses, less aggressive G1 mixed collection and more aggressive background collection: -XX:+UseG1GC -XX:MaxGCPauseMillis=37 -XX:+PerfDisableSharedMem -XX:G1HeapRegionSize=16M -XX:G1NewSizePercent=23 -XX:G1ReservePercent=20 -XX:SurvivorRatio=32 -XX:G1MixedGCCountTarget=3 -XX:G1HeapWastePercent=20 -XX:InitiatingHeapOccupancyPercent=10 -XX:G1RSetUpdatingPauseTimePercent=0 -XX:MaxTenuringThreshold=1 -XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5.0 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150 -XX:GCTimeRatio=99
Note: If you are using Java 20, it does not need the
-XX:G1ConcRefinementServiceIntervalMillis=150flag and will only print a warning with the flag
G1NewSizePercent and MaxGCPauseMillis can be used to tune the frequency and duration of your young generation collections. G1HeapWastePercent=18 should be removed if you are getting any old generation pauses on your setup. Alternatively, you can raise it and set G1MixedGCCountTarget to 2 or 1 to make mixed garbage collection even lazier, but will cost higher memory usage.
If we were to use Java >8 with only G1GC, client, it would look like this
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseG1GC -XX:MaxGCPauseMillis=37 -XX:+PerfDisableSharedMem -XX:G1HeapRegionSize=16M -XX:G1NewSizePercent=23 -XX:G1ReservePercent=20 -XX:SurvivorRatio=32 -XX:G1MixedGCCountTarget=3 -XX:G1HeapWastePercent=20 -XX:InitiatingHeapOccupancyPercent=10 -XX:G1RSetUpdatingPauseTimePercent=0 -XX:MaxTenuringThreshold=1 -XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5.0 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150 -XX:GCTimeRatio=99
If we were to use Java 8 with only G1GC, client, it would look like this
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+ParallelRefProcEnabled -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:+PerfDisableSharedMem -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -XX:MaxInlineLevel=15 -XX:MaxVectorSize=32 -XX:+UseCompressedOops -XX:ThreadPriorityPolicy=1 -XX:+UseNUMA -XX:+UseDynamicNumberOfGCThreads -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=350M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseFPUForSpilling -Dgraal.CompilerConfiguration=community -XX:+UseG1GC -XX:MaxGCPauseMillis=37 -XX:+PerfDisableSharedMem -XX:G1HeapRegionSize=16M -XX:G1NewSizePercent=23 -XX:G1ReservePercent=20 -XX:SurvivorRatio=32 -XX:G1MixedGCCountTarget=3 -XX:G1HeapWastePercent=20 -XX:InitiatingHeapOccupancyPercent=10 -XX:G1RSetUpdatingPauseTimePercent=0 -XX:MaxTenuringThreshold=1 -XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5.0 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150 -XX:GCTimeRatio=99
Longer pauses of garbage collection are more acceptable on servers. These flags are very close to the aikar defaults:
-XX:+UseG1GC -XX:MaxGCPauseMillis=130 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1NewSizePercent=28 -XX:G1HeapRegionSize=16M -XX:G1ReservePercent=20 -XX:G1MixedGCCountTarget=3 -XX:InitiatingHeapOccupancyPercent=10 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=0 -XX:SurvivorRatio=32 -XX:MaxTenuringThreshold=1 -XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150
Note: If you are using Java 20, it does not need the
-XX:G1ConcRefinementServiceIntervalMillis=150flag and will only print a warning with the flag
If we were to use Java >8 with only G1GC, server, it would look like this
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseG1GC -XX:MaxGCPauseMillis=130 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1NewSizePercent=28 -XX:G1HeapRegionSize=16M -XX:G1ReservePercent=20 -XX:G1MixedGCCountTarget=3 -XX:InitiatingHeapOccupancyPercent=10 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=0 -XX:SurvivorRatio=32 -XX:MaxTenuringThreshold=1 -XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150
If we were to use Java 8 with only G1GC, server, it would look like this
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+ParallelRefProcEnabled -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:+PerfDisableSharedMem -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -XX:MaxInlineLevel=15 -XX:MaxVectorSize=32 -XX:+UseCompressedOops -XX:ThreadPriorityPolicy=1 -XX:+UseNUMA -XX:+UseDynamicNumberOfGCThreads -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=350M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseFPUForSpilling -Dgraal.CompilerConfiguration=community -XX:+UseG1GC -XX:MaxGCPauseMillis=130 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1NewSizePercent=28 -XX:G1HeapRegionSize=16M -XX:G1ReservePercent=20 -XX:G1MixedGCCountTarget=3 -XX:InitiatingHeapOccupancyPercent=10 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=0 -XX:SurvivorRatio=32 -XX:MaxTenuringThreshold=1 -XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150
Warning: In order to use these flags you will need a larger amount of memory as well as a better CPU.
-XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:+PerfDisableSharedMem -XX:G1HeapRegionSize=16M -XX:G1NewSizePercent=23 -XX:G1ReservePercent=20 -XX:SurvivorRatio=32 -XX:G1MixedGCCountTarget=1 -XX:G1HeapWastePercent=30 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1RSetUpdatingPauseTimePercent=0 -XX:MaxTenuringThreshold=1 -XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5.0 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150 -XX:GCTimeRatio=99
If we were to use Java >8 with only aggressive G1GC, client, it would look like this
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:+PerfDisableSharedMem -XX:G1HeapRegionSize=16M -XX:G1NewSizePercent=23 -XX:G1ReservePercent=20 -XX:SurvivorRatio=32 -XX:G1MixedGCCountTarget=1 -XX:G1HeapWastePercent=30 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1RSetUpdatingPauseTimePercent=0 -XX:MaxTenuringThreshold=1 -XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5.0 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150 -XX:GCTimeRatio=99
If we were to use Java 8 with only aggressive G1GC, client, it would look like this
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+ParallelRefProcEnabled -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:+PerfDisableSharedMem -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -XX:MaxInlineLevel=15 -XX:MaxVectorSize=32 -XX:+UseCompressedOops -XX:ThreadPriorityPolicy=1 -XX:+UseNUMA -XX:+UseDynamicNumberOfGCThreads -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=350M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseFPUForSpilling -Dgraal.CompilerConfiguration=community -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:+PerfDisableSharedMem -XX:G1HeapRegionSize=16M -XX:G1NewSizePercent=23 -XX:G1ReservePercent=20 -XX:SurvivorRatio=32 -XX:G1MixedGCCountTarget=1 -XX:G1HeapWastePercent=30 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1RSetUpdatingPauseTimePercent=0 -XX:MaxTenuringThreshold=1 -XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5.0 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150 -XX:GCTimeRatio=99
If we were to use Java >8 with only aggressive G1GC, server, it would look like this
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:+PerfDisableSharedMem -XX:G1HeapRegionSize=16M -XX:G1NewSizePercent=23 -XX:G1ReservePercent=20 -XX:SurvivorRatio=32 -XX:G1MixedGCCountTarget=1 -XX:G1HeapWastePercent=30 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1RSetUpdatingPauseTimePercent=0 -XX:MaxTenuringThreshold=1 -XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5.0 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150 -XX:GCTimeRatio=99
If we were to use Java 8 with only aggressive G1GC, server, it would look like this
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+ParallelRefProcEnabled -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:+PerfDisableSharedMem -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -XX:MaxInlineLevel=15 -XX:MaxVectorSize=32 -XX:+UseCompressedOops -XX:ThreadPriorityPolicy=1 -XX:+UseNUMA -XX:+UseDynamicNumberOfGCThreads -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=350M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseFPUForSpilling -Dgraal.CompilerConfiguration=community -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:+PerfDisableSharedMem -XX:G1HeapRegionSize=16M -XX:G1NewSizePercent=23 -XX:G1ReservePercent=20 -XX:SurvivorRatio=32 -XX:G1MixedGCCountTarget=1 -XX:G1HeapWastePercent=30 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1RSetUpdatingPauseTimePercent=0 -XX:MaxTenuringThreshold=1 -XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5.0 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150 -XX:GCTimeRatio=99
Note: If you are using Java 20, it does not need the
-XX:G1ConcRefinementServiceIntervalMillis=150flag and will only print a warning with the flag
-XX:ConcGCThreads=[Some Number] controls the maximum number of background threads the garbage collector is allowed to use, and defaults to the calculation logical (hyperthreaded) cores / 4. Recent versions of Java will reduce the number of garbage collection threads, if needed.
In some cases (especially with ZGC or Shenandoh garbage collection) you want to increase this thread cap past the default. I recommend "2" on CPUs with 4 threads, and [number of real cores - 2] on most other CPUs, but you may need to change and test around with this parameter. If it's too low, garbage collection will not keep up with Minecraft, and the game will stutter and/or start eating large amounts of RAM and crash. If it's too high, it might slow the game down, especially if you are running Java 8.
No other "threading" flags like ParallelGCThreads or JVMCIThreads are necessary, as they are enabled by default with good automatic settings in Java 8+.
The terms Enterprise Edition (EE) and Community Edition (CE) are now deprecated from GraalVM with a rebranding from Oracle. In the past, you had to be a Oracle subscriber to use the Enterprise Edition which had the features we want or use the Community Edition, now the public version which is just GraalVM have these features for free to the public, the new versions also include ZGC which is recommended to use with GraalVM over using its G1GC collector
GraalVM is a new Java VM from Oracle that can improve the performance of (modded and vanilla) Minecraft. While client FPS gains are modest, server-side workloads like chunk generation can get a 20%+ boost.
Download it from these direct links from Oracle:
Select GraalVM versions are also available on the AUR and on Oracle Linux's repositories
Most up-to-date downloads, no account needed
Note: If you are using Java >20, it does not need the
-XX:G1ConcRefinementServiceIntervalMillis=150flag and will only print a warning with the flag
I highly recommend using GraalVM Java 21 with generational ZGC where possible as of 1.20.5. In older versions if the modpack is not explicitly compatible with Java 21 then fallback to previous recommendations. GraalVM Java 21 uses generational ZGC and does have a large performance boost. GraalVM Java 21 with generational ZGC in-use is the current best recommendation as of 1.20.5 for both server and client.
Java 21
-
Windows AMD64 (64-bit): https://download.oracle.com/graalvm/21/latest/graalvm-jdk-21_windows-x64_bin.zip
-
Linux AMD64 (64-bit): https://download.oracle.com/graalvm/21/latest/graalvm-jdk-21_linux-x64_bin.tar.gz
-
Linux AARCH64 (ARM 64-bit): https://download.oracle.com/graalvm/21/latest/graalvm-jdk-21_linux-aarch64_bin.tar.gz
-
Mac AMD64 (64-bit): https://download.oracle.com/graalvm/21/latest/graalvm-jdk-21_macos-x64_bin.tar.gz
-
Mac AARCH64 (ARM 64-bit): https://download.oracle.com/graalvm/21/latest/graalvm-jdk-21_macos-aarch64_bin.tar.gz
Java 20
-
Windows AMD64 (64-bit): https://download.oracle.com/graalvm/20/latest/graalvm-jdk-20_windows-x64_bin.zip
-
Linux AMD64 (64-bit): https://download.oracle.com/graalvm/20/latest/graalvm-jdk-20_linux-x64_bin.tar.gz
-
Linux AARCH64 (ARM 64-bit): https://download.oracle.com/graalvm/20/latest/graalvm-jdk-20_linux-aarch64_bin.tar.gz
-
Mac AMD64 (64-bit): https://download.oracle.com/graalvm/20/latest/graalvm-jdk-20_macos-x64_bin.tar.gz
-
Mac AARCH64 (ARM 64-bit): https://download.oracle.com/graalvm/20/latest/graalvm-jdk-20_macos-aarch64_bin.tar.gz
Java 17
-
Windows AMD64 (64-bit): https://download.oracle.com/graalvm/17/latest/graalvm-jdk-17_windows-x64_bin.zip
-
Linux AMD64 (64-bit): https://download.oracle.com/graalvm/17/latest/graalvm-jdk-17_linux-x64_bin.tar.gz
-
Linux AARCH64 (ARM 64-bit): https://download.oracle.com/graalvm/17/latest/graalvm-jdk-17_linux-aarch64_bin.tar.gz
-
Mac AMD64 (64-bit): https://download.oracle.com/graalvm/17/latest/graalvm-jdk-17_macos-x64_bin.tar.gz
-
Mac AARCH64 (ARM 64-bit): https://download.oracle.com/graalvm/17/latest/graalvm-jdk-17_macos-aarch64_bin.tar.gz
Unfortunately, I am no longer able to supply public free to download Java 11 and 8 links, however, you can look for current and archived versions of GraalVM on the current listing of Oracle's website and on their Java download page.
If you do have an Oracle account, you can use these links:
Most up-to-date Enterprise Edition downloads, account needed, these do not have ZGC
Java 11
-
Windows AMD64 (64-bit): https://download.oracle.com/otn/utilities_drivers/oracle-labs/graalvm-ee-java11-windows-amd64-22.3.3.zip
-
Linux AMD64 (64-bit): https://download.oracle.com/otn/utilities_drivers/oracle-labs/graalvm-ee-java11-linux-amd64-22.3.3.tar.gz
-
Linux AARCH64 (ARM 64-bit): https://download.oracle.com/otn/utilities_drivers/oracle-labs/graalvm-ee-java11-linux-aarch64-22.3.3.tar.gz
-
Mac AMD64 (64-bit): https://download.oracle.com/otn/utilities_drivers/oracle-labs/graalvm-ee-java11-darwin-amd64-22.3.3.tar.gz
Java 8
-
Windows AMD64 (64-bit): https://download.oracle.com/otn/utilities_drivers/oracle-labs/graalvm-ee-java8-windows-amd64-21.3.7.zip
-
Linux AMD64 (64-bit): https://download.oracle.com/otn/utilities_drivers/oracle-labs/graalvm-ee-java8-linux-amd64-21.3.7.tar.gz
-
Mac AMD64 (64-bit): https://download.oracle.com/otn/utilities_drivers/oracle-labs/graalvm-ee-java8-darwin-amd64-21.3.7.tar.gz
These releases are not Java installers. You need to manually replace your launcher's version of Java, or use a Minecraft launcher that supports specifying your Java path. I recommend ATLauncher, Prism Launcher or GDLauncher. When specifying a java path, navigate to the "bin" folder in the GraalVM download and use javaw.exe or java.exe (javaw.exe is typically the most recommended as it will not have an additional console window/command prompt while java.exe will).
Alternatively, you can install it system-wide by following Oracle's guide
For servers, you need to replace the "java" command in your server start sh/bat file with the full path to Graalvm java, in quotes.
Be sure to set -Dgraal.VectorizeSIMD to false if you run shaders.
Arguments for GraalVM 11, 17, & 20:
-XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:AllocatePrefetchStyle=3 -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:+EagerJVMCI -Dgraal.TuneInlinerExploration=1 -Dgraal.CompilerConfiguration=enterprise
You must use G1GC or ZGC with these arguments. GraalVM currently doesn't work with Shenandoah's garbage collector.
If we were to use Java >21 with GraalVM Java Arguments and Generational ZGC, it would look like this
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseZGC -XX:AllocatePrefetchStyle=1 -XX:-ZProactive -XX:+UseZGC -XX:AllocatePrefetchStyle=1 -XX:-ZUncommit -XX:+ZGenerational
If we were to use Java >8 with GraalVM Java Arguments and ZGC, it would look like this
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseZGC -XX:AllocatePrefetchStyle=1 -XX:-ZProactive -XX:+UseZGC -XX:AllocatePrefetchStyle=1 -XX:-ZProactive
If we were to use Java >8 with GraalVM Java Arguments and G1GC, it would look like this (Client)
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseG1GC -XX:MaxGCPauseMillis=37 -XX:+PerfDisableSharedMem -XX:G1HeapRegionSize=16M -XX:G1NewSizePercent=23 -XX:G1ReservePercent=20 -XX:SurvivorRatio=32 -XX:G1MixedGCCountTarget=3 -XX:G1HeapWastePercent=20 -XX:InitiatingHeapOccupancyPercent=10 -XX:G1RSetUpdatingPauseTimePercent=0 -XX:MaxTenuringThreshold=1 -XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5.0 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150 -XX:GCTimeRatio=99 -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:AllocatePrefetchStyle=3 -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:+EagerJVMCI -Dgraal.TuneInlinerExploration=1 -Dgraal.CompilerConfiguration=enterprise
If we were to use Java >8 with GraalVM Java Arguments and G1GC, it would look like this (Server)
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseG1GC -XX:MaxGCPauseMillis=130 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1NewSizePercent=28 -XX:G1HeapRegionSize=16M -XX:G1ReservePercent=20 -XX:G1MixedGCCountTarget=3 -XX:InitiatingHeapOccupancyPercent=10 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=0 -XX:SurvivorRatio=32 -XX:MaxTenuringThreshold=1 -XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150 -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:AllocatePrefetchStyle=3 -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:+EagerJVMCI -Dgraal.TuneInlinerExploration=1 -Dgraal.CompilerConfiguration=enterprise
It is also possible to get Java 8 versions of GraalVM (EE) from the 21.X section on the Oracle site, and use these arguments:
If we were to use Java <=8 with GraalVM (EE's) Java Arguments, it would look like this
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+ParallelRefProcEnabled -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -XX:AllocatePrefetchStyle=1 -XX:ThreadPriorityPolicy=1 -XX:+UseNUMA -XX:+UseDynamicNumberOfGCThreads -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=350M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseFPUForSpilling -XX:+EnableJVMCI -XX:+UseJVMCICompiler -XX:+EagerJVMCI -Dgraal.TuneInlinerExploration=1 -Dgraal.CompilerConfiguration=enterprise -Dgraal.UsePriorityInlining=true -Dgraal.Vectorization=true -Dgraal.OptDuplication=true -Dgraal.DetectInvertedLoopsAsCounted=true -Dgraal.LoopInversion=true -Dgraal.VectorizeHashes=true -Dgraal.EnterprisePartialUnroll=true -Dgraal.VectorizeSIMD=true -Dgraal.StripMineNonCountedLoops=true -Dgraal.SpeculativeGuardMovement=true -Dgraal.InfeasiblePathCorrelation=true
GraalVM 22.3.0 fixes all known Minecraft compatibility bugs
If you run an older, Java 8-based version of GraalVM, there are some potential issues:
-
VectorizeSIMDturns entities invisible with shader mods like Optifine, Iris or Occulus, but only under certain conditions. This will be fixed in GraalVM EE 22.3.0. See: oracle/graal#4849- Be sure to set
-Dgraal.VectorizeSIMDtofalseif you run shaders.
- Be sure to set
-
GraalVM CE and EE both break constellation rendering in 1.16.5 Astral Sorcery. This is possibly related to the shader bug. See: HellFirePvP/AstralSorcery#1963
I have not observed any server-side bugs yet.
If you run into any other mod issues you can trace back to GraalVM, please create a Github issue. Generally, you can work around them by disabling major dgraal optimization flags, or by finding the right function with Dgraal.PrintCompilation=true, and working around it with -Dgraal.GraalCompileOnly=~... once you find the miscompiled function.
This is a fantastic repo for finding performance mods: https://github.com/NordicGamerFE/usefulmods
There is no longer any use for Optifine, even in 1.7.10.
For Forge/NeoForge use: Embeddium + Oculus (shaders)
For Fabric use: Sodium + Iris (shaders)
When using Linux, other kernels may outperform the original/base kernels.
An example of this is using the linux-tkg build system which allows you to select certain optimization patches. However, it should be noted, the actual performance gain is not tested and in reality may not show any real gains.
The flag -XX:+UseNUMA forces the enabling of NUMA.
-XX:+UseNUMA can be safely removed from AMD Ryzen MCM and Threadripper CPUs. The NUMA flag ensures that CPUs are able to access RAM uniformly, however, with AMD Ryzen MCM and Threadripper CPUs the cores already perform memory access uniformly. Typically, this flag may not even be needed as the Java Virtual Machine should now automatically detect if NUMA is actually needed. AMD Ryzen MCM and Threadripper CPUs should automatically disable this flag, however, you may want to manually remove it.
There may be slight increases or decreases in performance based upon the usage of this flag, however, with modern CPUs there should not be too much of a difference, as well as based upon RAM.
-
Run your Minecraft servers on the Clear Linux OS - It's by far the most optimized linux distribution out-of-the-box, and it has some other nice features (like a stateless config system). It also runs clients on AMD/Intel GPUs quite well.
-
Oracle Linux is also a good choice for servers, since its reasonably well optimized out-of-the-box and has Graalvm available via the package manager.
-
For Linux clients, Arch-based distros like CachyOS or EndeavorOS are excellent, as they have wide support for most hardware.
-
Make sure the Minecraft client is using your dedicated GPU if you have one! Check the F3 tab, and force Minecraft to use it in the "Windows Graphics Settings", not the AMD/Nvidia control panel (as they don't seem to work well).
-
Minecraft client linux users should check out Minecraft Wayland.
-
If you are running on an older system or have a low amount of memory, close everything in the background, including Discord, game launchers and your browser. Minecraft is resource intensive, and does not like other apps generating CPU interrupts or eating disk I/O, and memory.
-
Java arguments have the goal of improving server performance and client stuttering as a result of garbage collection, they do not have the intention of boosting client FPS. For that, running correct/up-to-date graphics drivers and performance mods is far more important
-
This guide assumes you have a decent amount of spare RAM when running Minecraft. If your setup is RAM constrained, try removing the following arguments in particular:
-XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M, and try the server G1GC arguments. -
IBM's OpenJ9 does save RAM, as its reputation would suggest, but is over 30% slower at server chunkgen in my tests. If there are any flags that make it competitive with OpenJDK, please open a discussion on Github or contact my Discord
-
EXCEPTION_ACCESS_VIOLATION - This may be caused by a few different things
- Ensure Minecraft is using your dedicated graphics card if you have one
- Try updating graphics drivers and other drivers
- Try restarting your computer and only running Minecraft and see if it works
- Reinstall your Java Runtime Environment
- Try reinstalling Minecraft
- (Weird-edge case) If you are using only vanilla try installing Forge/NeoForge with or without mods and test
- Aikar G1GC flag explanation
-XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptionssimply unlock more flags to be used. These can be listed with the-XX:+PrintFlagsFinaland-XX:+JVMCIPrintPropertiesflags, see Flag Dumps-XX:G1MixedGCCountTarget=3: This is how many oldgen gc blocks to target in "mixed" gc. These mixed collections are much slower, and the Minecraft client doesn't generate oldgen very quickly, so we can lower this value to 3, 2, or even 1 for shorter GC pauses.-XX:+UseNUMAenables optimizations for multisocket systems, if applicable. Not sure if this applies to MCM CPUs like Ryzen or Epyc, but its auto disabled if not applicable.-XX:-DontCompileHugeMethodsAllows huge methods to be compiled. Modded Minecraft has some of these, and we don't care about higher background compiler CPU usage.-XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000Enable optimization of larger methods. See here-XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194Mreserves more space for compiled code. All sections must "add up" toReservedCodeCacheSize. I have observed modded Minecraft run into the default 250 megabyte limit withXX:+PrintCodeCache, but even if its not filled, the larger size makes eviction of compiled code less aggressive.-XX:NmethodSweepActivity=1(default 10) keeps "cold" code in the cache for a longer time. There is no risk of "filling up" the code cache either, as cold code is more aggressively removed as it fills up.This is a popular option, but not used here, as it's benching slower. Maybe its useful on low memory systems?-XX:+UseStringDeduplication-XX:+UseFastUnorderedTimeStampsAvoid system calls for getting the time. The impact of this will vary per system, but we aren't really concerned with logging timestamp accuracy.-XX:+UseCriticalJavaThreadPriorityNothing should preempt the Minecraft threads. GC and Compiler threads can wait.-XX:ThreadPriorityPolicy=1Use a wider range of thread priorities. Requires sudo on linux to work. Some JDKs (like Graal) enable this by default, but some don't.-XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150: Optimizes G1GC's concurrent collection threads, still being tested-XX:G1RSetUpdatingPauseTimePercent=0: We want all this work to be done in the G1GC concurrent threads, not the pauses.-XX:G1HeapWastePercent=18Don't bother collecting from old gen until its above this percent. This avoids triggering slower "mixed" young generation GCs, which is fine since Minecraft (with sufficient memory) doesn't fill the old gen that fast. Idea from here-XX:GCTimeRatio=99As a goal, 1% of CPU time should be spent on garbage collection. Default is 12, which seems way too low. The default for Java 8 was 99.-XX:AllocatePrefetchStyle=3Generate one prefetch instruction per cache line. More aggressive prefetching is generally useful on newer CPUs with large caches. It seems to break ZGC. See Github-Dgraal.LoopRotation=trueA non default optimization, will probably be default soon.-Dgraal.TuneInlinerExploration=1Spend more time making inlining decisions. For Minecraft, we want the C2 compiler to be as slow and aggressive as possible.- Most other
-Dgraalarguments are enabled by default, and are either there as a sanity check, for debugging or as a failsafe (if, for instance, someone unknowingly disables JVCMI with some other flag). - Many Java 8 flags (such as
-XX:MaxInlineLevel=15 -XX:MaxVectorSize=32) are just copied from the Java 17 defaults. Others (like+AggressiveOpts) are only non-default in some older Java 8 builds.
- More aggressive inlining, via
-Dgraal.BaseTargetSpending=160(default 120) in Graal and some other flags in OpenJDK. CPUs with larger caches might benefit from this. - OpenJDK flags which are disabled by default:
-XX:+AlignVector -XX:+OptoBundling -XX:+OptimizeFill -XX:+AlwaysCompileLoopMethods -XX:+EnableVectorAggressiveReboxing -XX:+EnableVectorSupport -XX:+OptoScheduling -XX:+UseCharacterCompareIntrinsics -XX:+UseCopySignIntrinsic -XX:+UseVectorStubs seems to hurt performance-Dgraal.LSRAOptimization=true-Dgraal.OptWriteMotion=trueandgraal.WriteableCodeCache=true, which do not seem stable, but may be more stable in GraalVM 22.3.0- Extreme
G1HeapWastePercentvalues.
A modernized overhaul of benchmarking is in-progress
Minecraft Version >= 1.20.5 = Java 21 Minecraft Version <= 1.20.4 and >= 1.16.5 = Java 17 Minecraft Version < 1.16.5 = Java 8
Exceptions for Minecraft versions can be made, for example in the modpack GTNH you want to use Java 21
If you do not know what Java version you are using, you are likely using a version of Java which only has the G1GC, in this case copy and paste the following into your JVM arguments for your client:
>=Java 17
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseG1GC -XX:MaxGCPauseMillis=37 -XX:+PerfDisableSharedMem -XX:G1HeapRegionSize=16M -XX:G1NewSizePercent=23 -XX:G1ReservePercent=20 -XX:SurvivorRatio=32 -XX:G1MixedGCCountTarget=3 -XX:G1HeapWastePercent=20 -XX:InitiatingHeapOccupancyPercent=10 -XX:G1RSetUpdatingPauseTimePercent=0 -XX:MaxTenuringThreshold=1 -XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5.0 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150 -XX:GCTimeRatio=99
Java 8
-Xmx8G -Xms8G -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+ParallelRefProcEnabled -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:+PerfDisableSharedMem -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -XX:MaxInlineLevel=15 -XX:MaxVectorSize=32 -XX:+UseCompressedOops -XX:ThreadPriorityPolicy=1 -XX:+UseNUMA -XX:+UseDynamicNumberOfGCThreads -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=350M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseFPUForSpilling -Dgraal.CompilerConfiguration=community -XX:+UseG1GC -XX:MaxGCPauseMillis=37 -XX:+PerfDisableSharedMem -XX:G1HeapRegionSize=16M -XX:G1NewSizePercent=23 -XX:G1ReservePercent=20 -XX:SurvivorRatio=32 -XX:G1MixedGCCountTarget=3 -XX:G1HeapWastePercent=20 -XX:InitiatingHeapOccupancyPercent=10 -XX:G1RSetUpdatingPauseTimePercent=0 -XX:MaxTenuringThreshold=1 -XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5.0 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150 -XX:GCTimeRatio=99
If you do know if you are using a version of Java with ZGC, Shenandoah, or GraalVM support then you should check ZGC, Shenandoah, or GraalVM, chances are, however, you are likely not if you previously didn't know about it.
Note: See Launchers and Memory Allocation for important information
