A «Killed» status with no crash report, no stack trace and no warning is one of the more disorienting things a server owner sees — because unlike almost every other failure, this one is not the game software's fault, and the game software never gets a chance to say anything about it.
Why the kill is instant and silent
A container's memory limit is enforced by the operating system kernel, not by Java. When total memory use — Java's heap, plus everything Java allocates outside the heap, plus every other process in the container — crosses that limit, the kernel does not ask nicely. It sends a signal that terminates the process immediately, with no chance for Java to log an exception, write a crash report, or even flush its own output. One moment the server is running; the next, the process no longer exists.
This is also why swap is disabled by design rather than an oversight: swap would let a server exceeding its memory limit slow to a crawl instead of being killed, trading a fast, clean failure for a slow, degraded one that is often worse for every player connected at the time — and it would do that at the cost of the NVMe I/O performance the rest of the platform is built around.
What actually uses memory, beyond -Xmx
| Consumer | Counts against the container limit? |
|---|---|
The Java heap, up to -Xmx | Yes — this is what the flag controls |
| Thread stacks (one per plugin thread, per connection handler) | Yes, and not included in -Xmx |
| Direct/off-heap buffers (used heavily by Netty for networking) | Yes, and not included in -Xmx |
| Memory-mapped region files | Yes, though the kernel can reclaim this more readily under pressure |
| Any other process in the container | Yes — a web map plugin, a bundled proxy, anything else running alongside |
-Xmx set too close to the container limitSetting -Xmx to the full memory allocation leaves nothing for everything on the table above. A server with a 4 GB plan and -Xmx4G is not using all 4 GB safely — it is guaranteeing an OOM kill the moment thread stacks and networking buffers need their share, which happens under ordinary load, not unusual load. Leaving 10–20% of the plan's memory unassigned to -Xmx is what actually uses the plan safely.
Diagnosing which kind of OOM this is
- Check whether it happens at a predictable time or grows worse over sessions
A leak climbs steadily across a session and eventually kills regardless of headroom. A headroom problem kills at roughly the same memory level every time, often tied to peak player count.
- Watch the memory graph across a full session, not just at the crash
A steady climb that never comes back down between quiet periods is the signature of a leak — usually a plugin holding references to entities, players or chunks it should be releasing.
- If it is headroom, lower
-Xmx, not raise the plan firstA crash from
-Xmxset too high is a configuration problem a plan upgrade happens to mask rather than fix — worth ruling out before spending on more memory the same misconfiguration would eventually fill too.
The server runs through a full busy session — the point where it previously died — with memory settling into the sawtooth pattern of normal garbage collection rather than climbing to the ceiling.