← All posts
minecraftserver-managementperformanceoptimizationjvm

Aikar's Flags vs MeowIce's Flags: What Each Set of JVM Arguments Actually Does

What each flag in Aikar's and MeowIce's JVM argument presets does to Minecraft's G1 garbage collector, where the two sets differ, and which one fits your server.

ChunkPod Team · · 8 min read

Aikar's Flags vs MeowIce's Flags: What Each Set of JVM Arguments Actually Does

Aikar's flags and MeowIce's flags are two of the most copied JVM argument presets for Minecraft servers, and both exist to make the Java garbage collector cause less lag. They tune the same collector, G1GC, but they aim it at different pause-time targets and disagree on how aggressively to reclaim memory. This post walks through what each flag does, where the two sets pick different defaults, and why.

Why the flags exist at all

A Minecraft server is one big Java process. Every tick, plugins spawn short-lived objects: packets, entity references, tick contexts, temporary lists. Java's garbage collector has to clean those up while the server keeps ticking. If a collection pauses the JVM for too long, TPS drops, players see rubber-banding, and the tick loop skips.

Java 8 and later ship with the G1 garbage collector, which splits the heap into fixed-size regions and collects them in slices small enough to hit a pause-time goal. G1's defaults are tuned for generic server workloads, not for a game loop that needs to run something every 50 milliseconds. Aikar's flags and MeowIce's flags are two different opinions on how to retune G1 for that game loop.

Aikar's flags

Aikar was a PaperMC developer, and the flags he published are the ones you'll see quoted in almost every "how do I fix TPS" thread. They target a server with at least 6 to 10 GB of heap, and they assume you'd rather have consistent tick times than the smallest possible heap footprint.

The core of the set:

  • -XX:+UseG1GC turns on the G1 collector. On modern Java it's already the default, but Aikar states it so the rest of the flags apply.
  • -XX:+ParallelRefProcEnabled lets G1 use multiple threads to process references (weak, soft, phantom). Minecraft creates a lot of these, so parallelising the sweep cuts pause time.
  • -XX:MaxGCPauseMillis=200 sets the target pause. G1 sizes its collection slices to fit inside this budget. 200 ms is generous by tick standards (a Minecraft tick is 50 ms), but Aikar treats it as an upper bound rather than a per-tick target.
  • -XX:+UnlockExperimentalVMOptions unlocks the flags in the next block. On modern Java a lot of these have been promoted out of experimental status, but the flag is harmless.
  • -XX:+DisableExplicitGC ignores any System.gc() call from mods or plugins. Some poorly written plugins call it, and without this flag a full stop-the-world collection can fire in the middle of a tick.
  • -XX:+AlwaysPreTouch touches every page of the heap at startup, forcing the OS to allocate it. Startup is slower, but you avoid page-fault pauses later when the heap grows into memory it hasn't used yet.
  • -XX:G1NewSizePercent=30 and -XX:G1MaxNewSizePercent=40 make the young generation much bigger than the G1 default. Minecraft produces a flood of short-lived garbage, and a bigger young generation lets almost all of it die there without ever getting promoted to old.
  • -XX:G1HeapRegionSize=8M fixes the region size at 8 MB. G1 chooses this automatically based on heap size, and it can pick regions that are too small on large heaps, making the remembered-set overhead worse.
  • -XX:G1ReservePercent=20 reserves 20% of the heap so G1 always has room to evacuate a region. Under-reserving causes "to-space exhausted" full GCs, which are the worst-case pause.
  • -XX:G1HeapWastePercent=5 tells G1 to keep collecting mixed regions until only 5% of the heap is wasted garbage. The default is 10, so Aikar's flags do slightly more work to keep the heap tidy.
  • -XX:G1MixedGCCountTarget=4 spreads old-generation cleanup over 4 mixed collections instead of the default 8. Fewer, larger mixed collections.
  • -XX:InitiatingHeapOccupancyPercent=15 starts concurrent marking when the heap is only 15% full. The default is 45. Aikar wants marking to start early so a mixed collection is always ready before the heap fills up.
  • -XX:G1MixedGCLiveThresholdPercent=90 lets G1 include regions with up to 90% live data in mixed collections.
  • -XX:G1RSetUpdatingPauseTimePercent=5 limits how much of each pause is spent updating remembered sets.
  • -XX:SurvivorRatio=32 shrinks survivor spaces, which fits the "almost everything dies young" pattern the rest of the flags assume.
  • -XX:+PerfDisableSharedMem turns off the hsperfdata file and removes a small source of jitter when the disk is busy.
  • -XX:MaxTenuringThreshold=1 promotes surviving objects to the old generation after one collection. Because the young generation is so large, anything that survives a young collection is usually long-lived anyway, so there's no point copying it back and forth.

The rest of Aikar's set is bookkeeping. The -Dusing.aikars.flags property is just a marker so Paper prints a friendly startup message.

The overall pattern is a huge young generation, an early marking trigger, and a conservative reserve so the collector never runs out of room. It trades some memory efficiency for very steady tick times.

MeowIce's flags

MeowIce's flags are a newer preset from the modded and high-population server community. They keep the shape of Aikar's set (still G1GC, still AlwaysPreTouch, still DisableExplicitGC) but push the tuning harder in a few places, and they add flags that only exist in more recent JDK builds.

Where MeowIce's set differs:

  • A lower MaxGCPauseMillis. MeowIce aims closer to 130 ms rather than 200. G1 responds by picking smaller collection slices, which run more often but individually finish faster. On a modpack server with many entities per chunk, this keeps single-tick spikes down.
  • A larger G1HeapRegionSize. MeowIce uses 16 MB regions instead of 8 MB. Bigger regions mean fewer regions to track, smaller remembered sets, and less per-region overhead. It costs a little precision in what G1 can collect in one slice, which is fine because the pause target is doing that work anyway.
  • A lower InitiatingHeapOccupancyPercent. MeowIce drops it to around 10, several points below Aikar's 15. Concurrent marking starts even earlier, which is useful on servers that fill the heap fast (chunk loading storms, big modded ticks).
  • A smaller G1MixedGCCountTarget. MeowIce uses 3 instead of 4. Old-generation cleanup finishes in fewer mixed collections. Each one does more work, but there are fewer of them.
  • -XX:G1RSetUpdatingPauseTimePercent=0. Aikar caps remembered-set update work at 5% of each pause. MeowIce moves it out of the pause entirely, pushing that work onto concurrent refinement threads. It saves pause time at the cost of more background CPU.
  • Concurrent refinement tuning. MeowIce's set adds flags such as G1ConcRefinementServiceIntervalMillis, G1ConcRSHotCardLimit, and G1ConcMarkStepDurationMillis. These control how eagerly the concurrent GC threads work in the background. The intent is to keep the collector doing steady, small units of work between ticks so it never has to catch up during a pause.
  • SATB buffer tuning. SATB is the "snapshot at the beginning" write barrier that G1 uses to track object changes during concurrent marking. Tuning G1SATBBufferEnqueueingThresholdPercent changes when marked-object buffers get flushed. MeowIce nudges this so marking finishes faster on servers with high mutation rates.

The pattern is different from Aikar's. Instead of a huge young generation that catches almost everything, MeowIce leans on the concurrent side of G1: mark earlier, refine remembered sets in the background, keep pauses short by moving work out of them. It makes G1 more responsive at the cost of more background work. On a beefy dedicated box with cores to spare, that trade is usually free. On a small server with only 2 or 3 cores, the extra concurrent work can steal CPU from the main server thread, and Aikar's more relaxed defaults may actually behave better.

Picking between them

There's no single answer, but a rough guide:

  • Small vanilla, Paper or Fabric SMP, 4 to 8 GB of heap, a couple of cores. Aikar's flags are the safe pick. They were designed for this size of server, and the extra concurrent work in MeowIce's set won't pay for itself.
  • Big Paper or Purpur server, 12 GB or more, dedicated hardware. MeowIce's flags tend to give flatter tick times, because the lower pause target and earlier marking match a heap that fills quickly.
  • Modded server (Forge, NeoForge, Fabric, Quilt) with heavy chunkloading. Try MeowIce's flags first. Modded worlds mutate the heap fast, and the more aggressive marking cadence handles that pattern well. If you see CPU pressure on the main thread, fall back to Aikar's.
  • Java 21 or newer. Both sets still work, but some of Aikar's +UnlockExperimentalVMOptions flags are now stable, and MeowIce's set is closer to what the JDK does by default. The gap between the two shrinks on newer Java.

Neither set is magic. If your server is dropping TPS because a plugin ticks 200,000 entities per second, no GC tuning will save it. Flags matter when the collector is the bottleneck, not when the tick loop is.

Generating your own set

Both presets need to be sized to your actual heap. Copy-pasting Aikar's flags for a 2 GB server, or MeowIce's flags for 32 GB, gives you the wrong young-generation size and the wrong region size. The values in this post are the shape of the flags, not the exact numbers you should ship with.

If you'd rather not calculate the sizing yourself, ChunkPod's JVM Arguments Generator at chunkpod.com/tools builds a ready-to-paste startup command for Vanilla, Paper, Forge or Fabric, in either Aikar or MeowIce style, scaled to the amount of RAM you're giving the server. It runs in the browser and doesn't need an account. ChunkPod is in early access as a host, but the tools are free to use even if you're not on the waitlist.