Minecraft

Aikar's Flags and JVM Tuning for Minecraft

What Aikar's JVM flags do for Minecraft servers, the full recommended set, how to size the heap and leave headroom, when to consider ZGC, and common mistakes.

On this page
  1. Why the JVM needs tuning
  2. The flags
  3. What the important ones do
  4. Sizing the heap correctly
  5. Java version
  6. What about ZGC?
  7. How to tell whether GC is your problem
  8. Common mistakes
  9. On managed hosting
  10. Summary

Minecraft servers run on Java, and Java’s default garbage collection settings aren’t tuned for a game server that creates huge numbers of short-lived objects every tick. Aikar’s flags — a set of JVM options published by Aikar, a long-time contributor to the Paper project — are the community standard for fixing that. This article explains what they do and how to use them well.

Why the JVM needs tuning

Every tick, a Minecraft server creates many temporary objects — positions, packets, block states — and throws them away almost immediately. Java’s garbage collector (GC) reclaims that memory. If collection is inefficient, you get GC pauses: moments where the server stops to clean up, felt by players as lag spikes.

Aikar’s flags configure the G1 garbage collector so that short-lived objects are cleaned up cheaply and pauses stay short and predictable.

The flags

For servers with up to about 12 GB of heap:

java -Xms10G -Xmx10G \
  -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 server.jar --nogui

For heaps larger than 12 GB, a few values change:

-XX:G1NewSizePercent=40 -XX:G1MaxNewSizePercent=50 -XX:G1HeapRegionSize=16M
-XX:G1ReservePercent=15 -XX:InitiatingHeapOccupancyPercent=20

What the important ones do

-Xms and -Xmx (set equal) — minimum and maximum heap. Setting them equal gives the JVM its full heap at startup and avoids resizing. Combined with -XX:+AlwaysPreTouch, the memory is allocated up front, so the server doesn’t stall later while the operating system hands out pages.

-XX:+UseG1GC — the G1 collector, which divides the heap into regions and collects the most garbage-heavy ones first, aiming for predictable pauses.

-XX:MaxGCPauseMillis=200 — G1’s pause-time target. Along with the other settings, this keeps pauses comfortably within limits for a game running at 20 ticks per second.

G1NewSizePercent / G1MaxNewSizePercent — reserve a large share of the heap (30–40%) for the young generation, where new objects live. Minecraft creates so many short-lived objects that a big young generation lets most of them die cheaply without being copied into older generations.

-XX:MaxTenuringThreshold=1 and -XX:SurvivorRatio=32 — objects that survive one collection are promoted quickly instead of being copied back and forth. For Minecraft’s allocation pattern this reduces wasted work.

-XX:InitiatingHeapOccupancyPercent=15 — start background (concurrent) collection of the old generation early, so the old generation never fills up and forces a long full collection.

-XX:G1HeapRegionSize — region size; larger heaps use larger regions.

-XX:+DisableExplicitGC — ignores System.gc() calls from plugins, which would otherwise trigger full collections and lag spikes.

-XX:+PerfDisableSharedMem — stops the JVM writing performance statistics to a memory-mapped file, avoiding occasional disk-related stalls.

-XX:+ParallelRefProcEnabled — processes references with multiple threads to shorten pauses.

The two -D properties at the end don’t change behaviour; they mark that the flags are in use, which helps when troubleshooting with the Paper community.

Sizing the heap correctly

The heap is not all the memory Java uses. Metaspace, thread stacks, the JIT code cache and native buffers — used heavily for networking — live outside it. If -Xmx equals your server’s total memory, the process exceeds its limit and gets killed.

Leave headroom:

Total memory Suggested -Xms/-Xmx
4 GB 3000M
6 GB 4500–5000M
8 GB 6500M
12 GB 10G
16 GB 13–14G

For how much memory your server needs in the first place, see how much RAM a Minecraft server needs.

Java version

Use the Java version your Minecraft version requires: Java 21 for 1.20.5 and newer, Java 17 for 1.18–1.20.4. Aikar’s flags work on both. Newer Java versions also bring GC improvements, which is another reason to keep up to date.

What about ZGC?

Java’s ZGC does almost all its work concurrently, with pauses usually under a millisecond regardless of heap size. On Java 21, generational ZGC (-XX:+UseZGC -XX:+ZGenerational) is a genuine option for large servers:

java -Xms16G -Xmx16G -XX:+UseZGC -XX:+ZGenerational -XX:+AlwaysPreTouch -jar server.jar --nogui

Trade-offs: ZGC uses more CPU and memory than G1 for the same workload, and benefits appear mostly on large heaps with plenty of CPU. For typical servers under ~12–16 GB, well-tuned G1 with Aikar’s flags remains the safe, proven choice. If you try ZGC, measure with spark before and after rather than assuming it’s better.

How to tell whether GC is your problem

  • In a spark profile, look at GC activity alongside tick times. Regular lag spikes that line up with GC pauses point to memory settings.
  • /spark gc shows collection counts and times.
  • If MSPT is high between pauses, GC isn’t the problem — look at entities, chunks and plugins instead. See fixing Minecraft server lag.

Common mistakes

  • Allocating all the memory to the heap. The server gets killed with no Java error. Leave headroom.
  • Huge heaps “just in case”. More heap doesn’t fix CPU lag and can make each collection larger.
  • Copying old flag sets with outdated options like -XX:+UseConcMarkSweepGC, which newer Java versions have removed — the server won’t start.
  • Mixing collectors — specifying both G1 and ZGC options.
  • Forgetting --nogui on headless servers, which tries to open a window and wastes resources.

On managed hosting

Many hosting panels, including the Pterodactyl-based panel Kerit Cloud uses, let you set the startup command or JVM flags for your server. On Kerit Cloud’s Minecraft hosting, the team sets up sensible flags and memory for your custom-quoted server, and you keep full panel access if you want to tune them yourself.

Summary

Aikar’s flags tune Java’s G1 collector for Minecraft’s flood of short-lived objects: a large young generation, quick promotion, early concurrent collection, ignored System.gc() calls and a pre-allocated, fixed-size heap. Set -Xms equal to -Xmx, leave 1–2 GB of headroom outside the heap, use the Java version your Minecraft version needs, and consider generational ZGC only for large servers — measuring with spark either way.