1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /** 25 * @test TestPeriodicCollection 26 * @requires vm.gc.G1 27 * @summary Verify that heap shrinks when the application is idle. 28 * @library /test/lib / 29 * @modules java.base/jdk.internal.misc 30 * @modules java.management/sun.management 31 * @build sun.hotspot.WhiteBox 32 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 33 * sun.hotspot.WhiteBox$WhiteBoxPermission 34 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. -Xms32M -Xmx128M -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=25 -XX:+UseG1GC -XX:G1PeriodicGCInterval=3000 -XX:+G1PeriodicGCInvokesConcurrent -Xlog:gc,gc+periodic=debug,gc+ergo+heap=debug TestPeriodicCollection 35 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. -Xms32M -Xmx128M -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=25 -XX:+UseG1GC -XX:G1PeriodicGCInterval=3000 -XX:-G1PeriodicGCInvokesConcurrent -Xlog:gc,gc+periodic=debug,gc+ergo+heap=debug TestPeriodicCollection 36 */ 37 38 import com.sun.management.HotSpotDiagnosticMXBean; 39 40 import gc.testlibrary.Helpers; 41 42 import java.lang.management.ManagementFactory; 43 import java.lang.management.MemoryUsage; 44 import java.util.ArrayList; 45 import java.util.List; 46 import java.text.NumberFormat; 47 import static jdk.test.lib.Asserts.*; 48 49 import sun.hotspot.WhiteBox; 50 51 public class TestPeriodicCollection { 52 53 public static final String MIN_FREE_RATIO_FLAG_NAME = "MinHeapFreeRatio"; 54 public static final String MAX_FREE_RATIO_FLAG_NAME = "MaxHeapFreeRatio"; 55 56 private static final List<List<byte[]>> garbage = new ArrayList(); 57 58 private static final long TOTAL_MEMORY = Runtime.getRuntime().totalMemory(); 59 private static final long MAX_MEMORY = Runtime.getRuntime().maxMemory(); 60 private static final int IDLE_TIME = 10 * 1000; 61 62 private static final int ARR_SIZE = 64 * 1024; // 64k 63 private static final int LISTS_COUNT = 10; 64 private static final int ARR_COUNT = (int) ((TOTAL_MEMORY / ARR_SIZE) / LISTS_COUNT); 65 66 public static void main(String[] args) { 67 if (ARR_COUNT == 0) { 68 System.out.println("Skipped. Heap is too small"); 69 return; 70 } 71 72 if (TOTAL_MEMORY + ARR_SIZE * ARR_COUNT > MAX_MEMORY) { 73 System.out.println("Skipped. Initial heap size is too close to max heap size."); 74 return; 75 } 76 77 new TestPeriodicCollection().test(); 78 } 79 80 private final void test() { 81 WhiteBox.getWhiteBox().fullGC(); 82 83 MemoryUsagePrinter.printMemoryUsage("init"); 84 85 allocate(); 86 MemoryUsagePrinter.printMemoryUsage("allocated"); 87 MemoryUsage muFull = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); 88 89 garbage.clear(); 90 try { 91 Thread.sleep(IDLE_TIME); 92 } catch (InterruptedException ie) { 93 System.err.println("Skipped. Failed to wait for idle collection"); 94 } 95 MemoryUsagePrinter.printMemoryUsage("free"); 96 MemoryUsage muFree = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); 97 98 assertLessThan(muFree.getCommitted(), muFull.getCommitted(), String.format( 99 "committed free heap size is not less than committed full heap size, heap hasn't been shrunk?%n" 100 + "%s = %s%n%s = %s", 101 MIN_FREE_RATIO_FLAG_NAME, 102 ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class) 103 .getVMOption(MIN_FREE_RATIO_FLAG_NAME).getValue(), 104 MAX_FREE_RATIO_FLAG_NAME, 105 ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class) 106 .getVMOption(MAX_FREE_RATIO_FLAG_NAME).getValue() 107 )); 108 } 109 110 private void allocate() { 111 112 for (int i = 0; i < LISTS_COUNT; i++) { 113 List<byte[]> stuff = new ArrayList(); 114 allocateList(stuff, ARR_COUNT, ARR_SIZE); 115 MemoryUsagePrinter.printMemoryUsage("allocate #" + (i+1)); 116 garbage.add(stuff); 117 } 118 } 119 120 private static void allocateList(List garbage, int count, int size) { 121 for (int i = 0; i < count; i++) { 122 garbage.add(new byte[size]); 123 } 124 } 125 } 126 127 /** 128 * Prints memory usage to standard output 129 */ 130 class MemoryUsagePrinter { 131 132 public static final NumberFormat NF = Helpers.numberFormatter(); 133 134 public static void printMemoryUsage(String label) { 135 MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); 136 float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted(); 137 System.out.format("[%-24s] init: %-7s, used: %-7s, comm: %-7s, freeRatio ~= %.1f%%%n", 138 label, 139 NF.format(memusage.getInit()), 140 NF.format(memusage.getUsed()), 141 NF.format(memusage.getCommitted()), 142 freeratio * 100 143 ); 144 } 145 }