Over a million developers have joined DZone.

Runtime Commited Heap Resizing

· Java Zone

What every Java engineer should know about microservices: Reactive Microservices Architecture.  Brought to you in partnership with Lightbend.

New day, new version of Java... nice :)

We used to update minor Java versions mostly due to security issues. But sometimes those minor updates brings us brand new, awesome features. So was for example with 7u40 which brought us awesome Mission Control known from JRockit. (If you are interested in tracking changes across Java updates take a look at
http://www.oracle.com/technetwork/java/javase/8all-relnotes-2226344.html for Java 8 orhttp://www.java.com/en/download/faq/release_changes.xml for Java 7) 

Same situation is now with versions 7u60 and 8u20. Since now flags MinHeapFreeRatio andMaxHeapFreeRatio became manageable, which means we can change its values... in runtime :) 

You can always check which flags in JVM are manageable by invoking

java -XX:+PrintFlagsFinal -XX:+UseG1GC -version |grep manageable
intx CMSAbortablePrecleanWaitMillis  = 100  {manageable}
intx CMSWaitDuration  = 2000  {manageable}
bool HeapDumpAfterFullGC  = false  {manageable}
bool HeapDumpBeforeFullGC  = false  {manageable}
bool HeapDumpOnOutOfMemoryError  = false  {manageable}
ccstr HeapDumpPath  =  {manageable}
uintx MaxHeapFreeRatio  = 70  {manageable}
uintx MinHeapFreeRatio  = 40  {manageable}
bool PrintClassHistogram  = false  {manageable}
bool PrintClassHistogramAfterFullGC  = false  {manageable}
bool PrintClassHistogramBeforeFullGC  = false  {manageable}
bool PrintConcurrentLocks  = false  {manageable}
bool PrintGC  = false  {manageable}
bool PrintGCDateStamps  = false  {manageable}
bool PrintGCDetails  = false  {manageable}
bool PrintGCTimeStamps  = false  {manageable}
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
Getting back to our flags. MinHeapFreeRatio defines minimum percentage of heap free after GC to avoid expansion, while MaxHeapFreeRation (as you can expect) describes maximum percentage of heap free after GC to avoid shrinking. 

Now let's see how this heap resizing works. At first we need to find java process right for testing. I'll going to use running IntelliJ IDEA.
As you know java pids can be found by invoking jps command:

jps -l
17136 com.intellij.idea.Main
We already know our testing pid, so it's good time to find out some heap statistics. We'll use jmapcommand to do that:
jmap -heap 17136
Attaching to process ID 17136, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.20-b23
using thread-local object allocation.
Garbage-First (G1) GC with 4 thread(s)
Heap Configuration:
MinHeapFreeRatio  = 40
MaxHeapFreeRatio  = 70
MaxHeapSize  = 2147483648 (2048.0MB)
NewSize  = 1363144 (1.2999954223632812MB)
MaxNewSize  = 1287651328 (1228.0MB)
OldSize  = 5452592 (5.1999969482421875MB)
NewRatio  = 2
SurvivorRatio  = 8
MetaspaceSize  = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize  = 17592186044415 MB
G1HeapRegionSize  = 1048576 (1.0MB)
Heap Usage:
G1 Heap:
regions  = 2048
capacity = 702545920 (670.0MB)
used  = 284513824 (271.3335266113281MB)
free  = 418032096 (398.6664733886719MB)
40.49754128527285% used
As you can see I'm using G1 GC with 2GB max heap size (-Xmx2g). Heap usage is about 40%. Now we should run full gc to clean up a little bit before playing.

jcmd 17136 GC.run
Then jmap one more time and we can see 
Heap Configuration:
MinHeapFreeRatio  = 40
MaxHeapFreeRatio  = 70
Heap Usage:
G1 Heap:
regions  = 2048
capacity = 439353344 (419.0MB)
used  = 135954032 (129.65586853027344MB)
free  = 303399312 (289.34413146972656MB)
30.944121367607025% used
Finally we're ready to start resezing. I will change value of MaxHeapFreeRatio flag by using jinfotool:

jinfo -flag MaxHeapFreeRatio=50 17136
After that we have to again run full gc to force resizing. And now our heap looks like that: 
Heap Configuration:
MinHeapFreeRatio  = 40
MaxHeapFreeRatio  = 50
Heap Usage:
G1 Heap:
regions  = 2048
capacity = 166723584 (159.0MB)
used  = 82849400 (79.01134490966797MB)
free  = 83874184 (79.98865509033203MB)
49.69266975450816% used
As you can see heap shrank from 419 to 159 MB.

Now we can try going in other way: 

jinfo -flag MaxHeapFreeRatio=90 17136
jinfo -flag MinHeapFreeRatio=85 17136
gives jmap output 

Heap Configuration:
MinHeapFreeRatio  = 85
MaxHeapFreeRatio  = 90
Heap Usage:
G1 Heap:
regions  = 2048
capacity = 465567744 (444.0MB)
used  = 69816504 (66.58220672607422MB)
free  = 395751240 (377.4177932739258MB)
14.995992505872572% used
Resizing worked one more time and heap capacity has increased from 159MB to 444MB. We described that minimum 85% of our heap capacity should be free, and that pointed JVM to resize the heap to gain at most 15% usage. Now we're waiting for runtime XMX changing ;)

Microservices for Java, explained. Revitalize your legacy systems (and your career) with Reactive Microservices Architecture, a free O'Reilly book. Brought to you in partnership with Lightbend.


Published at DZone with permission of Jakub Kubrynski, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}