Best JVM Flags for a Minecraft Server

Which JVM flags matter for a Minecraft server: the G1 set Paper publishes, how to size the heap against your RAM, and the GC logging that proves it.

Written by
Mihail Griniuc
Last updated
Checked against
Java 21 with Paper 1.21.11
Reading time
3 min

Short answer

Use the G1 flags Paper publishes, set -Xms equal to -Xmx and leave 1000 to 1500 MB for the JVM and OS. That is the whole answer: a tuned collector with a heap that does not resize, sized below your RAM rather than equal to it.

JVM flags are where people copy the longest command lines and understand them least. For a Minecraft server the picture is unusually simple: the allocation pattern is known, a public flag set exists for exactly this workload, and the heap size is the only number that has to be arithmetic.

This guide is the short version of what matters, where the flags come from, and how to tell that the JVM is behaving. Anything beyond this is tuning for its own sake.

Before you start

  • Control of the server start command, which panels and systemd units both give you
  • Java 21 for current Minecraft versions
  • A backup, because a bad flag set is a bad start

JVM flags and what each one does

FlagWhat it doesWhy it matters here
-Xms6G -Xmx6GInitial and maximum heapEqual values mean the heap never resizes during play
-XX:+UseG1GCSelects the G1 collectorHandles Minecraft's short-lived allocation pattern best
-XX:+AlwaysPreTouchCommits the heap at startupThe JVM stops faulting pages in while players are waiting
-XX:MaxGCPauseMillis=200Target pause lengthTells G1 how long a collection may take
-XX:+DisableExplicitGCBlocks System.gc()Stops plugins forcing collections mid-tick
-XX:+PerfDisableSharedMemSkips the hsperfdata fileHelps on hosts where shared memory is restricted
-Xlog:gc*:logs/gc.log:timeGC loggingShows whether the heap is healthy or leaking

1. Size the heap first, because every other flag assumes it

-Xmx is the maximum memory the JVM may use and -Xms is what it starts with. Set them equal: the heap never has to resize during play, and resizing is one of the sources of pauses people call lag.

Set the value below your RAM, not equal to it. Paper's documentation is explicit that the JVM and the operating system need roughly 1000 to 1500 MB beyond -Xmx, so 8 GB of RAM should get -Xmx6G. A host that is willing to say it accounts for the overhead can give you more, which is worth asking.

the heap numbers for common machines
8 GB RAM   -> -Xms6G -Xmx6G
12 GB RAM  -> -Xms10G -Xmx10G
16 GB RAM  -> -Xms13G -Xmx13G

2. Use the G1 flags Paper publishes, unchanged

The garbage collector is where most of the benefit is. Paper documents a set of G1 flags tuned for how Minecraft allocates: mostly short-lived objects, with a few long-lived ones such as loaded chunks. Copy that set from the Paper documentation and do not substitute flags from another project.

Two of them matter most. -XX:+UseG1GC selects the collector. -XX:+AlwaysPreTouch commits the whole heap at startup, so the JVM does not fault pages in while players are waiting. The rest tune the young and old generation sizes for this workload.

the flag set, from the PaperMC documentation
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
the same for a vanilla server
java -Xms4G -Xmx4G -XX:+UseG1GC -XX:+ParallelRefProcEnabled \
  -XX:MaxGCPauseMillis=200 -XX:+AlwaysPreTouch \
  -jar server.jar nogui

3. Turn on GC logging so the heap is not a mystery

Garbage collection logging records every collection with timings. It is how you tell a normal server from a leak: a healthy server logs collections every few seconds with the heap falling back after each one, while a leaking server logs collections constantly with the heap near full and barely dropping.

Java 11 and later use one flag. Older versions need the older set. Either way the file goes where you can read it later, and neither costs performance.

Java 11 and later
-Xlog:gc*:logs/gc.log:time,uptime:filecount=5,filesize=1M
Java 8 to 10
-Xloggc:gc.log -verbose:gc -XX:+PrintGCDetails \
  -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps \
  -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=1M

4. Restart and verify what the JVM is actually doing

Start the server and read the first lines. The JVM prints its version and the arguments it was given, which is the fastest way to catch a flag that did not make it into the command.

Then watch behaviour rather than theory: /tps during a normal session, and the GC log afterwards. If the collections are frequent but the heap returns to a low level each time, the server is fine. If it climbs towards -Xmx and stays there, something is holding memory, and the memory guide is the next step.

in game or console
/tps
/mspt

Good to know

  • Two flags are worth knowing because they change behaviour rather than performance. -XX:+DisableExplicitGC stops plugins that call System.gc() from forcing collections mid-tick. -XX:+PerfDisableSharedMem avoids creating the hsperfdata file, which matters on hosts where shared memory is restricted.
  • Panic settings such as -XX:+CrashOnOutOfMemoryError exist and are not defaults. Leave them off unless you are debugging a specific crash.
  • On a hosting panel you do not set these flags yourself; the platform sets the start command and the heap. Override it only if the panel documents how, because a manual heap can exceed what the platform accounts for and get the process killed.
  • Running with systemd shows where these flags live in a service unit.

Common questions

What is the best JVM flag set for Minecraft?

The G1 flags Paper publishes, with -Xms equal to -Xmx and the heap set about 1000 to 1500 MB below your RAM. That is the set Paper's own start script uses, and it is what the documentation and script generator produce.

How much RAM should I give a Minecraft server?

Enough that -Xmx is below your total RAM and the GC log shows headroom. A small world runs in 2 to 4 GB; Paper's guidance is 6 to 10 GB whatever the player count. The RAM calculator sizes it for your setup.

Do JVM flags affect a vanilla server too?

The heap and collector flags do, and vanilla benefits from them in the same way. The G1 tuning set is documented for Paper because that is where it was developed; the flags are not Paper-specific, but the values were tested on it.

Why did my server crash after I added flags?

Usually the heap. If -Xmx exceeds the memory the host actually gives you, the kernel kills the process and the log has no exception. Check the heap against the host's number, restart, and read the JVM's startup line to confirm the arguments you expected are the arguments it got.

Sources

Official documentation this guide was checked against.

Written and maintained by Mihail Griniuc. Last reviewed against Java 21 with Paper 1.21.11. Spotted a mistake or something out of date? Email [email protected].

Revision history
  • Rewritten as heap sizing, the published G1 set, and GC logging, with the flags attributed to the PaperMC page they come from.

Rather not run this on your own machine? PufferHost gives every player a free Minecraft server with 3 GB of RAM and 10 slots. Create a free server.