I'd like to detect when free memory is low (say 15% free) and take some action.
I tried using the Runtime memory indicators, but I seem to be getting inconsistent behavior.
Here's my test app:
import java.util.*;
public class Memory
{
static final int BYTES_PER_MB = 1024*1024;
public static void main(String[] args) {
Queue<byte[]> q = new LinkedList<>();
int allocated = 0;
while (true) {
q.add(new byte[BYTES_PER_MB * 100]);
allocated += 100;
System.out.printf("Allocated 100m (total allocated=%d)%n", allocated);
printMem();
}
}
public static void printMem() {
long max = Runtime.getRuntime().maxMemory() / BYTES_PER_MB;
long total = Runtime.getRuntime().totalMemory() / BYTES_PER_MB;
long free = Runtime.getRuntime().freeMemory() / BYTES_PER_MB;
long totalFree = free+(max-total); // allocated free + memory that can be allocated
System.out.printf("MEM: max=%dm, total=%dm, free=%d, (total free=%d)%n", max, total, free, totalFree);
}
}
Here are the results I'm getting:
JVM | Command | Total free before OOM
--------------------------------------------------------------------------------------------------
Oracle Java 1.8.0_191-b12 64-Bit Server | java -Xmx1024m -Xms10m Memory | 309
Oracle Java 1.8.0_191-b12 64-Bit Server | java -Xmx1024m Memory | 205
Oracle Java 11.0.2+9-LTS 64-Bit Server | java -Xmx1024m -Xms10m Memory | 12
Oracle Java 11.0.2+9-LTS 64-Bit Server | java -Xmx1024m Memory" | 12
The results make sense for Java 11, but I don't understand the results for Java 8.
- Why am I unable to allocate memory, even though I have more than enough? (I don't think it's a fragmentation issue, since the heap has mostly 100m chunks + it also fails if I allocate in 10m chunks)
- Why can I allocate even less if I specify a low
-Xmx? Shouldn't it only affect the initial heap size?


