Memory, heap & Java flags

Updated 13 Oct 2026

Your plan RAM is not your heap

This is the single most useful thing to understand about a Minecraft server's memory, and it explains most “I bought more RAM and it got worse” stories.

Your plan's RAM is the limit on the whole container. Inside it, Java carves out a heap for the game world, and then needs more memory on top of that for things that are not the heap at all:

WhatRoughlyGrows with
Heap: chunks, entities, plugin dataWhat you setPlayers, world size, plugins
Metaspace: loaded classes100–300 MBNumber of plugins
Thread stacks50–150 MBPlugins doing async work
GC and JVM internals100–200 MBHeap size
Direct buffers: networking50–200 MBPlayer count

So a 2 GB plan cannot run a 2 GB heap. Try it and the container hits its limit and gets killed, which looks exactly like a crash with no error in the log.

A kill leaves no stack trace

When the container exceeds its memory limit the process is terminated from outside. There is no OutOfMemoryError, no crash report, often no final log line. The console just ends and the server restarts. A clean stop with nothing before it is the signature.

Check what your server is actually doing

Open the Console tab and run:

Console
spark heapsummary

Or without spark, the plain version:

Console
/memory

What you want to see is used heap settling back down after each garbage collection. What you do not want is used heap climbing to the maximum and staying there, with the server pausing periodically. That is the JVM collecting over and over because it has nowhere to put anything.

Find your current setting

Open the Startup tab and look at the startup command and variables. One of these decides your heap:

FlagMeans
-Xmx3GMaximum heap is exactly 3 GB
-Xms3GStarting heap is 3 GB
-XX:MaxRAMPercentage=70Maximum heap is 70% of the container limit

The percentage trap on small plans

MaxRAMPercentage looks tidy, and it is the setting most likely to break a small server. The problem is that the overhead from step 1 is roughly fixed (it does not shrink with your plan), so the same percentage behaves completely differently at different sizes.

PlanAt 95%Left for everything elseResult
2 GB1,945 MB heap~103 MBKilled, usually within hours
4 GB3,891 MB heap~205 MBKilled under load
16 GB15,564 MB heap~820 MBUsually survives

A 2 GB server at 95% leaves about 100 MB for metaspace, thread stacks, GC structures and networking combined, which is less than the classes alone need once you have a dozen plugins loaded. It will die, and the console will show nothing.

70% is the number to use

-XX:MaxRAMPercentage=70 works across every plan size: 1.4 GB heap on a 2 GB plan, 11.2 GB on a 16 GB one, always with enough left over. If you prefer to be explicit, set -Xmx to your plan size minus about 600 MB and forget percentages entirely.

Check this after any plan change

A percentage is read from the container limit at boot, so changing plan silently changes your heap. Downgrading a 16 GB server to 2 GB takes the heap from 11 GB to 1.4 GB: the same world, a fraction of the room. Restart and re-check the numbers after every resize.

Flags worth setting, and ones to leave alone

Minecraft allocates and discards objects constantly, so the collector matters. The widely used baseline is Aikar's flag set, built around G1 and tuned to keep pauses short rather than maximise throughput:

Startup flags, 4 GB and above
-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

Two adjustments by size:

HeapChange
Under 4 GBDrop G1NewSizePercent to 20 and G1MaxNewSizePercent to 30
12 GB or moreRaise G1HeapRegionSize to 16M

Set Xms equal to Xmx

Give the JVM its full heap at startup rather than letting it grow. Growing the heap costs pauses at exactly the wrong moments, and on a dedicated server there is nothing else to save the memory for.

Leave the rest alone

Beyond this set, hand-tuning GC flags reliably makes things worse. In particular do not add -XX:+UseZGC or -XX:+UseShenandoahGC because a benchmark liked them; Minecraft's allocation pattern is not what they are built for, and nothing in Paper's own recommendations asks for them.

When the answer is not memory

Before upgrading a plan, be sure the symptom is actually memory pressure. These three get confused with it constantly:

SymptomMemory?Actually
Steady 15 TPS with players on, no pausesNoToo much work per tick: fixing lag
Total stops of 10 s+, then a catch-upUsually notA blocked tick: read the watchdog dump
Short regular pauses, heap pinned at maxYesGC thrashing: raise the heap or cut what fills it
Server disappears, no error, restartsYesContainer kill: heap too close to the plan limit

What fills a heap fastest

More RAM buys time; it does not remove the cause. Usually it is loaded chunks and entities, not players. Worth checking before you pay for a bigger plan:

Console
spark heapsummary
mobcaps

Common culprits: view-distance and simulation-distance left high, large mob farms, hoppers in bulk, and chunk-loading plugins that never unload what they touch. Dropping simulation-distance from 10 to 6 often does more for both memory and TPS than doubling the plan.

A safe starting point

If you want numbers to copy rather than a method, use these and move on:

PlanHeapReasonable for
2 GB-Xms1400M -Xmx1400MUp to ~8 players, few plugins
4 GB-Xms3G -Xmx3G~15 players, a normal plugin set
8 GB-Xms7G -Xmx7G~40 players, or a heavy modpack
16 GB-Xms14G -Xmx14GLarge servers, or a proxy network backend
Changes need a full restart

Startup flags are read once when the JVM launches. Editing the Startup tab while the server runs changes nothing until you stop and start it, and a /reload definitely will not do it.

Troubleshooting

I upgraded my plan and nothing improved

Check whether the heap actually grew. With a fixed -Xmx it does not, you are paying for memory the JVM was told never to use. Raise -Xmx to the new plan size minus about 600 MB and restart. If the heap was never the limit, see step 5; for a server that is slow rather than pausing, start with Fixing lag & low TPS.

The console ends mid-line with no error and the server restarts

Classic container kill. Your heap plus overhead is over the plan limit. Lower -Xmx by 512 MB, or switch to -XX:MaxRAMPercentage=70, and restart. If it happens within a minute of boot every time, the heap is set larger than the plan itself. Check for a leftover -Xmx from a bigger plan.

Java 8 or 11 images seem to ignore my plan size

Older JVMs do not reliably read container limits, so percentage flags behave unpredictably or get ignored. On those images always set -Xmx explicitly in megabytes. If nothing requires the old version, moving to a current Java image is worth doing for the collector alone.

Should I set Xms lower so the server uses less memory when quiet?

No. There is nothing else on the server to hand the memory to, and letting the heap grow buys pauses during play in exchange for an idle number nobody sees. Set -Xms equal to -Xmx.

Not sure what your flags should be? Open a ticket with your server ID and plan size and we will check your startup line against your world.
Open a ticket

More guides