Why you actually care about heap usage? as long as you set XMS (maximum heap) you are fine. Let java invoke GC when it seems fit. As long as you have free heap it is no point doing GC and freeing heap just for sake of having a lot of free heap.
If you want to limit memory allocated by process XMX is not enough. You should also limit native memory.
What you should care about is
- Memory leaks, consecutive Full GCs, GC starvation
- GC KPIs: Latency, throughput, footprint
- Object creation rate, promotion rate, reclamation rate…
- GC Pause time statistics: Duration distribution, average, count, average interval, min/max, standard deviation
- GC Causes statistics: Duration, Percentage, min/max, total
- GC phases related statistics: Each GC algorithm has several sub-phases. Example for G1: initial-mark, remark, young, full, concurrent mark, mixed
See https://blog.gceasy.io/2017/05/30/improving-your-performance-reports/ https://blog.gceasy.io/2017/05/31/gc-log-analysis-use-cases/ for more technical details. You could also analyze your GC logs using https://blog.gceasy.io/ it will help you understand how your JVM is using memory.