Overview
Mango by Radix IoT runs on the Java Virtual Machine (JVM). The JVM's memory allocation directly affects Mango's performance, stability, and ability to handle large numbers of data points. Too little memory causes crashes and slow performance; too much wastes server resources.
JVM Memory Basics
- Heap memory (-Xmx) — the main memory pool where Mango stores objects, caches, and runtime data. This is the most important setting to tune
- Initial heap (-Xms) — memory allocated at startup. Setting equal to -Xmx avoids dynamic resizing
- Metaspace — memory for class definitions. Rarely needs tuning for Mango
- Stack size (-Xss) — per-thread stack memory. Rarely needs tuning
Where to Set JVM Memory
Set heap flags in Mango's startup options file — not in mango.properties (formerly env.properties) for normal installs:
| Installation Type | Configuration Location |
|---|---|
| Linux (script or service) | <data directory>/start-options.sh (create if missing). The launcher resolves it from the paths.start.options property, which defaults to start-options.sh inside the data directory; the data directory itself defaults to <mango-home> unless paths.data is set. |
| Windows | No equivalent options file. The shipped launcher mango.cmd runs java -jar boot\ma-bootstrap.jar with no heap flags and reads neither start-options.sh nor mango.vmoptions — both are sourced by start-mango.sh on Linux only. Set heap through your Windows service wrapper's own configuration, or a JVM environment variable such as JDK_JAVA_OPTIONS. Confirm the supported route with Radix IoT before relying on it. |
Example for Linux (start-options.sh):
# Heap size — restart Mango after changing
MA_JAVA_OPTS="$MA_JAVA_OPTS -Xms2g -Xmx2g"
There is no Windows equivalent of this file. mango.cmd launches the bootstrap jar directly and reads no options file, so the snippet above applies to Linux only.
Mango also supports a JVM options file: paths.vm.options defaults to mango.vmoptions in the data directory, and when present the launcher passes it to the JVM as -XX:VMOptionsFile. Either mechanism works; start-options.sh is the one most installs use.
Verify what actually took effect: start-mango.sh prints "Starting Mango with options '…'" with the assembled MA_JAVA_OPTS before it launches the JVM. If your flags are not in that line, the file you edited is not the one being read.
Warning
Mango treats an out-of-memory error as fatal, because it relies on in-memory caches, and its shipped start-options.sh says these two “should be enabled for all production systems”. They are commented out by default, so on a production instance uncomment them: -XX:+ExitOnOutOfMemoryError to terminate the JVM rather than limp on, and -XX:+HeapDumpOnOutOfMemoryError (with -XX:HeapDumpPath=) to leave something to diagnose.
Two things about the shipped file are worth knowing before you copy from it. Its garbage-collection section offers UseConcMarkSweepGC, UseSerialGC, UseParallelGC and UseParallelOldGC but not G1, and UseConcMarkSweepGC was removed from the JVM in Java 14 — so that list is older than the Java you are probably running. And its last block is nine --add-exports / --add-opens flags marked "required to use the chroniclePointValueCache module": Chronicle is not only an extra memory consumer, it needs JVM flags to run at all. The same flags ship in mango.vmoptions.
Recommended Memory Sizes
Heap depends on point count and on how those points are driven. Polling data sources hold far less in the heap than script-driven points, so the same point count can need very different heaps.
| Data Points | Mostly polling (BACnet, Modbus, SNMP) | Mixed | Script heavy (Meta, Scripting) |
|---|---|---|---|
| Under 500 | 1 to 2 GB | 2 GB | 2 to 3 GB |
| 500 to 5,000 | 2 to 4 GB | 4 GB | 4 to 6 GB |
| 5,000 to 20,000 | 4 to 8 GB | 6 to 10 GB | 8 to 12 GB |
| 20,000 to 50,000 | 8 to 12 GB | 10 to 16 GB | 12 to 20 GB |
| 50,000 to 150,000 | 12 to 20 GB | 16 to 24 GB | 20 to 32 GB |
Sizing server RAM: budget the heap figure above plus 3 GB for the JVM's non-heap memory, plus the database allocation, plus 4 GB or more for the OS and page cache. Account separately for anything else running outside the JVM allocation — Chronicle's off-heap point value cache and any co-hosted services need memory of their own, and none of it comes out of -Xmx.
Tip
Do not size from the table alone if the instance is already running. Measure the live heap with the garbage-collection method below and size against the measured figure.
Symptoms of Insufficient Memory
| Symptom | Likely Cause |
|---|---|
| Mango crashes with "OutOfMemoryError" in ma.log | Heap too small for the workload |
| UI becomes very slow periodically | Frequent garbage collection pauses (heap nearly full) |
| Data sources stop polling temporarily | GC pauses interrupting poll threads |
| Charts take long to load | Not enough memory to cache query results |
| Mango uses 100% CPU for extended periods | GC thrashing — trying to free memory but can't |
Monitoring JVM Memory
Monitor memory usage to validate your settings:
- Internal metrics — System status is superadmin-only and not in the menu, so open Administration → Admin home, click More details on the Server status card, and choose Internal metrics under Choose a section. It lists
JVM used memory (MB),JVM free memory (MB), andJVM maximum available memory (MB), so you can compare the live heap against the -Xmx you set - Internal Data Source — create data points for JVM memory, enabling trending and alerts
- ma.log — OutOfMemoryError entries indicate immediate action needed
- OS tools —
top,htop, or Task Manager show total Java process memory
Tuning Tips
- Set -Xms equal to -Xmx — prevents JVM from spending time resizing the heap. Allocate what you need upfront
- Don't over-allocate — giving the JVM 28 GB on a 32 GB server leaves no room for the OS and database. This causes swapping and worse performance than a smaller heap
- Use G1GC — the G1 garbage collector (default in modern Java) handles large heaps well. No change needed for most deployments
- Restart after changes — JVM memory settings only take effect at startup
- Monitor after changing — watch memory usage for 24-48 hours after a change to verify the new settings are appropriate
Garbage Collection Tuning
For most Mango deployments, the default garbage collector works fine. If you experience GC pauses:
# Enable G1GC with pause target (if not already default)
MA_JAVA_OPTS="$MA_JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
Only tune GC settings if you're experiencing specific problems and have monitoring data to guide decisions.
Measuring the Right Heap Size with Garbage Collection
Garbage collection is the most reliable way to learn the heap a given instance actually needs. Force a collection, then read the live set:
PID=$(cat <data directory>/ma.pid)
JAVA=<JAVA_HOME>/bin
sudo -u mango $JAVA/jcmd $PID GC.run
sudo -u mango $JAVA/jcmd $PID GC.heap_info
The PID file is ma.pid in the data directory by default (paths.pid.file), written by start-mango.sh when it launches the JVM.
Read the used figure from the line beginning garbage-first heap.
Four rules make the measurement valid:
- Run
GC.runfirst.GC.heap_infoon its own reports live objects plus uncollected garbage. On one measured instance that was 14.5 GiB against a true 10.26 GiB — a 41% overstatement that would have wasted 4 GB of heap. - Wait for a full daily cycle. Script engines compile lazily: a function is compiled and retained the first time it runs, so scripts on hourly, daily, or weekly schedules contribute nothing to the heap until they fire. Measure at least 24 hours after start, and longer if any schedule is weekly or monthly.
- Measure with the final configuration in place. A live set measured with a module disabled is not valid once that module is enabled. One instance read 4.36 GiB with
chroniclePointValueCachedisabled and 10.26 GiB with it enabled; sizing against the earlier number produced a heap that thrashed. - Run the tools as the JVM's own user.
jstatreads a shared memory file owned by the service account and fails with Operation not permitted for any other user — including root, in some configurations.
Troubleshooting
| Issue | Cause | Fix |
|---|---|---|
| OutOfMemoryError: Java heap space | Heap too small | Increase -Xmx; check for memory leaks if problem persists |
| Mango won't start after increasing memory | More RAM requested than available | Reduce -Xmx to fit within available RAM |
| OS is swapping heavily | JVM + database + OS exceed physical RAM | Reduce JVM heap or add more RAM |
| Intermittent slowness every few minutes | GC pauses on undersized heap | Increase heap; monitor GC logs |
Summary
JVM memory configuration is critical for Mango stability and performance. Set -Xmx from both point count and workload type — script-heavy deployments need materially more heap than polling-only ones at the same point count. Keep -Xms equal to -Xmx. Size server RAM as heap plus 3 GB plus the database allocation plus 4 GB or more for the OS and page cache, and measure the live heap with GC.run followed by GC.heap_info rather than sizing from the table alone. Address OutOfMemoryErrors immediately — they indicate the system is undersized for the workload.