Capacity and cost Required
Size the runtime's memory to the box
Set the language runtime's memory limits below the container or service limit, so it collects garbage before the system kills it.
How to do it
Runtimes size their heap from the machine, not from the container, and keep freed memory reserved. Cap the main heap at about half the service limit. On small boxes, also shrink the young generation, which can reserve tens of megabytes. Examples are Node's --max-old-space-size and --max-semi-space-size, Java's -XX:MaxRAMPercentage and Go's GOMEMLIMIT. Read files on request instead of loading every one at start. Measure peak memory under the load test after each change.
Example
# systemd drop-in for a Node service with a 260 MB limit
[Service]
Environment="NODE_OPTIONS=--max-old-space-size=128 --max-semi-space-size=4"
MemoryHigh=200M
MemoryMax=260M
# Java in a container: heap as a share of the container limit
java -XX:MaxRAMPercentage=50 -jar app.jar
# Go: a soft limit the garbage collector works to stay under
GOMEMLIMIT=200MiB ./app
How to check
The load test reports peak memory below 80 percent of the service limit, and its 95th percentile response time is unchanged by the caps.
Measured
On a reference site with a 260 MB service limit, shrinking the young generation took peak memory under load from 190 to 139 MB. Response times stayed at 42 ms.
For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers operations playbook: https://agentwranglers.se/playbook/operations/capacity-and-cost/runtime-memory-limits.