Sign inCreate server
Minecraft

What Are Aikar's Flags? A Complete Guide for Minecraft Servers

Aikar's flags explained line by line: what each JVM argument does, why Xms must equal Xmx, and how to pick the right values for your server's RAM.

5 min read#aikar flags#minecraft server#jvm#g1gc#performance#paper

If you run a Minecraft server, you have probably been told to "use Aikar's flags" — usually without any explanation of what they do. This guide walks through them line by line, so you can decide what fits your server instead of pasting a command you don't understand.

The short version

Aikar's flags are a hand-tuned set of JVM arguments published by Daniel Ennis (Aikar), a PaperMC contributor. They configure the G1 garbage collector for the way Minecraft allocates memory.

Minecraft creates and discards an enormous number of short-lived objects every tick — entities, chunk sections, packets. Default JVM settings are tuned for general server applications, not for that pattern. The result is garbage collection pauses that land in the middle of a tick and show up in game as lag spikes.

Aikar's flags trade a little extra CPU and memory for shorter, more frequent collections. You lose a bit of raw throughput; you gain a much flatter tick time. For a game server, that is the right trade.

The flags, explained

Garbage collector selection

texto
-XX:+UseG1GC
-XX:+ParallelRefProcEnabled
-XX:MaxGCPauseMillis=200

UseG1GC selects the G1 collector, which splits the heap into regions and collects them incrementally rather than stopping everything at once.

ParallelRefProcEnabled processes reference objects in parallel instead of on a single thread. Minecraft creates a lot of them, and this step is a common source of pause time.

MaxGCPauseMillis=200 is a target, not a guarantee. It tells G1 how much pause it is allowed to aim for when sizing its work. Lowering it further is a common mistake: G1 responds by collecting more often, which can make things worse.

Young generation sizing

texto
-XX:G1NewSizePercent=30
-XX:G1MaxNewSizePercent=40
-XX:G1HeapRegionSize=8M
-XX:SurvivorRatio=32
-XX:MaxTenuringThreshold=1

This is the core of the tuning. By default G1 keeps the young generation small and grows it reluctantly. Minecraft's garbage is overwhelmingly short-lived, so a large young generation means most objects die there and never get promoted.

MaxTenuringThreshold=1 says: if an object survives one collection, stop copying it around and promote it. Copying survivors repeatedly costs more than promoting them early.

Mixed collections

texto
-XX:InitiatingHeapOccupancyPercent=15
-XX:G1MixedGCLiveThresholdPercent=90
-XX:G1MixedGCCountTarget=4
-XX:G1HeapWastePercent=5
-XX:G1ReservePercent=20
-XX:G1RSetUpdatingPauseTimePercent=5

InitiatingHeapOccupancyPercent=15 starts the concurrent marking cycle early — at 15% occupancy instead of the default 45%. Starting early means the collector is never racing to catch up, which is when long pauses happen.

G1ReservePercent=20 keeps a fifth of the heap in reserve so a sudden allocation spike (a player loading a dense chunk area) doesn't trigger an emergency full collection.

Safety and startup

texto
-XX:+UnlockExperimentalVMOptions
-XX:+DisableExplicitGC
-XX:+AlwaysPreTouch
-XX:+PerfDisableSharedMem

DisableExplicitGC ignores System.gc() calls. Some plugins call it directly, which forces a full stop-the-world collection for no good reason.

AlwaysPreTouch writes to every page of the heap at startup so the OS commits the memory up front. Startup takes a few seconds longer; you stop paying that cost in the middle of gameplay.

Why -Xms and -Xmx must be equal

This is the part most guides get wrong.

texto
java -Xms8G -Xmx8G ...

The usual advice — "set a low minimum so the server only uses what it needs" — is backwards for a game server. When the heap grows, the JVM has to commit memory and resize its internal structures, and that happens while the server is running. With AlwaysPreTouch enabled, an unequal Xms also defeats the point of pre-touching.

Setting them equal means the heap is allocated once, at startup, and never resized. There is no "saving" to be had: a JVM that is allowed to grow will grow, and reach the same number anyway.

Choosing your heap size

Two rules that matter more than the flags themselves:

Do not allocate all of your system RAM. The JVM heap is not the JVM's total memory footprint — thread stacks, metaspace, direct buffers and the JIT's compiled code all live outside it. Leave at least 1–2 GB for the operating system and the JVM's own overhead.

More is not always better. A larger heap means each collection has more to scan. Servers with 24 GB heaps often perform worse than the same server with 12 GB, because pause times scale with the amount of live data.

If you are unsure what your server actually needs, our RAM calculator estimates it from your player count and server type.

Above 12 GB, change the region sizing

Aikar publishes a second set of values for large heaps:

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

The reason is simple: G1 caps the number of heap regions it manages. With 8 MB regions and a very large heap you end up with too many, and the bookkeeping itself becomes the bottleneck.

What these flags will not fix

Be realistic about what you are buying. Aikar's flags reduce garbage collection pauses. They do not fix:

  • A plugin doing blocking I/O on the main thread
  • Chunk generation lag on a fresh world
  • Redstone or entity-heavy farms
  • A server on oversold shared hardware with no guaranteed CPU

If your tick time is bad and steady, garbage collection is probably not your problem. If it is mostly fine with periodic spikes, it probably is.

Generate your own

Rather than copying values from a guide that may not match your RAM, you can generate the flags for your exact heap size — it picks the right region sizing automatically and gives you a ready-to-run start script.

Sources

Was this article helpful?