Nowadays, JVM-based applications can benefit from elasticity and density of container technology. However, there are still some issues that prevent unleashing the full potential of Java and containers “marriage.”
Releasing unused but committed Heap memory by the major JVM implementations based on OpenJDK, in most cases, is not performed automatically, or requires specific knowledge to be configured.
To solve this problem and make Java RAM usage in containers more efficient, Jelastic team was collaborating with different experts involved in JVM development. We periodically published articles highlighting this issue and motivating the community to help in finding a solution. As a result, attention to this topic increased, and new improvements were introduced in different Garbage Collection implementations.
Moreover, we initiated and sponsored development of a patch to OpenJDK which improves elasticity and enables fully automated vertical scaling of Java applications that rely on G1 garbage collector. This work introduces new command line options for heap sizing that allows the JVM to scale its memory resources vertically. In particular, the proposed solution is to promptly return unused committed memory to the operating system.
There is a necessity to rethink the Garbage Collection (GC) policies that control how much and when the heap memory is given back to the operating system. Currently, G1 returns memory from the Java heap only at a Full GC that is rarely performed.
As a result, in most cases, Java heap will not be released unless forced externally. Such behavior is particularly disadvantageous in scalable container environments when JVM uses a fraction of assigned memory resources due to inactivity or a small load. This results in customers overpaying for unused resources, and cloud providers not being able to fully utilize their hardware.
In order to overcome this issue, we introduce additional logic into the JVM to trigger a heap reduction whenever the amount of unused memory is significant. It can be performed at any time by configurable options, not only during regular GC cycles.
During inactivity of the application, G1 will periodically trigger a concurrent cycle due to the following conditions:
- More than G1PeriodicGCInterval milliseconds have passed since any previous garbage collection pause and there is no concurrent cycle in progress at this point. A value of zero indicates that periodic garbage collections to promptly reclaim memory are disabled.
- The average one-minute system load value as returned by the getloadavg() call on the JVM host system (e.g. container) is below G1PeriodicGCSystemLoadThreshold. This condition is ignored if G1PeriodicGCSystemLoadThreshold is zero.
If either of these conditions is not met, the current periodic garbage collection is cancelled and will be reconsidered when G1PeriodicGCInterval time passes.
The offered solution is already implemented in the OpenJDK 12. This improvement will allow Java users to save a significant amount of resources and thus money, as well as help cloud providers to better utilize their infrastructure and introduce more flexible billing model based on real usage not on the VM limits.
The stated problem of Java elasticity, details on performed experiments, and specifics of the corresponding OpenJDK patch were presented at Oracle Code One 2018 during the session of Ruslan Synytsky, Jelastic CEO. Feel free to review the presentation below.
Have any questions about scaling Java vertically and horizontally? Want to try it in practice? Get in touch with us or just register for a free trial.