Two servers can run the identical jar, the identical plugins, and the identical player count — and one stutters every couple of minutes while the other does not. The difference is very often not the server at all. It is how the Java garbage collector was told to behave.
What the garbage collector actually does to your tick
Java manages memory for you: objects your code stops referencing eventually get reclaimed by the garbage collector, automatically. The catch is that reclaiming memory is itself work, and by default the JVM's garbage collector picks when to do that work based on its own heuristics — heuristics tuned for general-purpose software, not for a program that has 50 milliseconds to finish a tick and no more.
When the collector decides a pause is needed, every thread — including the one running your world — stops until it finishes. A small, frequent pause is invisible. A collector that lets garbage build up and then does one large collection produces exactly the symptom people describe as «the server freezes for a second every few minutes», and it is the collector's own design doing that, not a bug.
What a good flag set is actually doing
| Goal | How it is achieved |
|---|---|
| A modern garbage collector | Switching to G1GC (default on recent Java, but worth confirming) instead of an older collector tuned for throughput over latency |
| Short, predictable pauses instead of rare long ones | A max-pause-time target that tells the collector to do more frequent, smaller collections rather than fewer large ones |
| Less collection overall | Region sizing and heap percentage thresholds tuned for the access pattern of a game server rather than a generic Java application |
Garbage collection has to work harder as the heap fills, and a heap that is consistently near full will pause no matter how the collector is tuned — flags change how gracefully it degrades, not how much memory exists. If tuning the flags did not fix a stutter, the honest next question is whether the plan has enough memory for what is actually running, not which flag set to try next.
Applying a flag set
- Set them as JVM arguments, before
-jarThey configure the Java process itself, not the Minecraft server — order in the startup command matters, and they have to come before the jar is named.
- Match
-Xmsand-Xmxto the same valueA heap that is allowed to grow and shrink triggers extra collection work resizing itself. Fixing both to the plan's allocation removes that cost entirely.
- Change one thing and watch, not five
Flag sets interact. Testing the whole set at once tells you whether it helped; testing pieces individually tells you which piece did.
A server can have plenty of memory free by the panel's graph and still pause, because the pause is about how the collector is choosing to reclaim memory, not about whether memory ran out. Reading CPU alongside memory during a stutter usually shows a brief spike on one core — the collector doing its work — which is the signature to look for.