Wed, 03 Sep 2014 09:25:44 +0200
Merge
jwilhelm@7095 | 1 | /* |
jwilhelm@7095 | 2 | * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. |
jwilhelm@7095 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
jwilhelm@7095 | 4 | * |
jwilhelm@7095 | 5 | * This code is free software; you can redistribute it and/or modify it |
jwilhelm@7095 | 6 | * under the terms of the GNU General Public License version 2 only, as |
jwilhelm@7095 | 7 | * published by the Free Software Foundation. |
jwilhelm@7095 | 8 | * |
jwilhelm@7095 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
jwilhelm@7095 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
jwilhelm@7095 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
jwilhelm@7095 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
jwilhelm@7095 | 13 | * accompanied this code). |
jwilhelm@7095 | 14 | * |
jwilhelm@7095 | 15 | * You should have received a copy of the GNU General Public License version |
jwilhelm@7095 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
jwilhelm@7095 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
jwilhelm@7095 | 18 | * |
jwilhelm@7095 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
jwilhelm@7095 | 20 | * or visit www.oracle.com if you need additional information or have any |
jwilhelm@7095 | 21 | * questions. |
jwilhelm@7095 | 22 | */ |
jwilhelm@7095 | 23 | |
jwilhelm@7095 | 24 | /** |
jwilhelm@7095 | 25 | * @test TestHumongousShrinkHeap |
tschatzl@7096 | 26 | * @bug 8036025 8056043 |
jwilhelm@7095 | 27 | * @summary Verify that heap shrinks after GC in the presence of fragmentation due to humongous objects |
jwilhelm@7095 | 28 | * @library /testlibrary |
jwilhelm@7095 | 29 | * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 -XX:+UseG1GC -XX:G1HeapRegionSize=1M -verbose:gc TestHumongousShrinkHeap |
jwilhelm@7095 | 30 | */ |
jwilhelm@7095 | 31 | |
jwilhelm@7095 | 32 | import java.lang.management.ManagementFactory; |
jwilhelm@7095 | 33 | import java.lang.management.MemoryUsage; |
jwilhelm@7095 | 34 | import java.util.ArrayList; |
jwilhelm@7095 | 35 | import java.util.List; |
jwilhelm@7095 | 36 | import sun.management.ManagementFactoryHelper; |
jwilhelm@7095 | 37 | import static com.oracle.java.testlibrary.Asserts.*; |
jwilhelm@7095 | 38 | |
jwilhelm@7095 | 39 | public class TestHumongousShrinkHeap { |
jwilhelm@7095 | 40 | |
jwilhelm@7095 | 41 | public static final String MIN_FREE_RATIO_FLAG_NAME = "MinHeapFreeRatio"; |
jwilhelm@7095 | 42 | public static final String MAX_FREE_RATIO_FLAG_NAME = "MaxHeapFreeRatio"; |
jwilhelm@7095 | 43 | |
jwilhelm@7095 | 44 | private static final ArrayList<ArrayList<byte[]>> garbage = new ArrayList<>(); |
jwilhelm@7095 | 45 | private static final int PAGE_SIZE = 1024 * 1024; // 1M |
jwilhelm@7095 | 46 | private static final int PAGES_NUM = 5; |
jwilhelm@7095 | 47 | |
jwilhelm@7095 | 48 | |
jwilhelm@7095 | 49 | public static void main(String[] args) { |
jwilhelm@7095 | 50 | new TestHumongousShrinkHeap().test(); |
jwilhelm@7095 | 51 | } |
jwilhelm@7095 | 52 | |
jwilhelm@7095 | 53 | private final void test() { |
jwilhelm@7095 | 54 | System.gc(); |
jwilhelm@7095 | 55 | MemoryUsagePrinter.printMemoryUsage("init"); |
jwilhelm@7095 | 56 | |
jwilhelm@7095 | 57 | eat(); |
jwilhelm@7095 | 58 | MemoryUsagePrinter.printMemoryUsage("eaten"); |
jwilhelm@7095 | 59 | MemoryUsage muFull = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); |
jwilhelm@7095 | 60 | |
jwilhelm@7095 | 61 | free(); |
jwilhelm@7095 | 62 | MemoryUsagePrinter.printMemoryUsage("free"); |
jwilhelm@7095 | 63 | MemoryUsage muFree = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); |
jwilhelm@7095 | 64 | |
jwilhelm@7095 | 65 | assertLessThan(muFree.getCommitted(), muFull.getCommitted(), String.format( |
jwilhelm@7095 | 66 | "committed free heap size is not less than committed full heap size, heap hasn't been shrunk?%n" |
jwilhelm@7095 | 67 | + "%s = %s%n%s = %s", |
jwilhelm@7095 | 68 | MIN_FREE_RATIO_FLAG_NAME, |
jwilhelm@7095 | 69 | ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MIN_FREE_RATIO_FLAG_NAME).getValue(), |
jwilhelm@7095 | 70 | MAX_FREE_RATIO_FLAG_NAME, |
jwilhelm@7095 | 71 | ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MAX_FREE_RATIO_FLAG_NAME).getValue() |
jwilhelm@7095 | 72 | )); |
jwilhelm@7095 | 73 | } |
jwilhelm@7095 | 74 | |
jwilhelm@7095 | 75 | private void eat() { |
jwilhelm@7095 | 76 | int HumongousObjectSize = Math.round(.9f * PAGE_SIZE); |
jwilhelm@7095 | 77 | System.out.println("Will allocate objects of size=" + |
jwilhelm@7095 | 78 | MemoryUsagePrinter.humanReadableByteCount(HumongousObjectSize, true)); |
jwilhelm@7095 | 79 | |
jwilhelm@7095 | 80 | for (int i = 0; i < PAGES_NUM; i++) { |
jwilhelm@7095 | 81 | ArrayList<byte[]> stuff = new ArrayList<>(); |
jwilhelm@7095 | 82 | eatList(stuff, 100, HumongousObjectSize); |
jwilhelm@7095 | 83 | MemoryUsagePrinter.printMemoryUsage("eat #" + i); |
jwilhelm@7095 | 84 | garbage.add(stuff); |
jwilhelm@7095 | 85 | } |
jwilhelm@7095 | 86 | } |
jwilhelm@7095 | 87 | |
jwilhelm@7095 | 88 | private void free() { |
jwilhelm@7095 | 89 | // do not free last one list |
jwilhelm@7095 | 90 | garbage.subList(0, garbage.size() - 1).clear(); |
jwilhelm@7095 | 91 | |
jwilhelm@7095 | 92 | // do not free last one element from last list |
jwilhelm@7095 | 93 | ArrayList stuff = garbage.get(garbage.size() - 1); |
jwilhelm@7095 | 94 | stuff.subList(0, stuff.size() - 1).clear(); |
jwilhelm@7095 | 95 | System.gc(); |
jwilhelm@7095 | 96 | } |
jwilhelm@7095 | 97 | |
jwilhelm@7095 | 98 | private static void eatList(List garbage, int count, int size) { |
jwilhelm@7095 | 99 | for (int i = 0; i < count; i++) { |
jwilhelm@7095 | 100 | garbage.add(new byte[size]); |
jwilhelm@7095 | 101 | } |
jwilhelm@7095 | 102 | } |
jwilhelm@7095 | 103 | } |
jwilhelm@7095 | 104 | |
jwilhelm@7095 | 105 | /** |
jwilhelm@7095 | 106 | * Prints memory usage to standard output |
jwilhelm@7095 | 107 | */ |
jwilhelm@7095 | 108 | class MemoryUsagePrinter { |
jwilhelm@7095 | 109 | |
jwilhelm@7095 | 110 | public static String humanReadableByteCount(long bytes, boolean si) { |
jwilhelm@7095 | 111 | int unit = si ? 1000 : 1024; |
jwilhelm@7095 | 112 | if (bytes < unit) { |
jwilhelm@7095 | 113 | return bytes + " B"; |
jwilhelm@7095 | 114 | } |
jwilhelm@7095 | 115 | int exp = (int) (Math.log(bytes) / Math.log(unit)); |
jwilhelm@7095 | 116 | String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i"); |
jwilhelm@7095 | 117 | return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); |
jwilhelm@7095 | 118 | } |
jwilhelm@7095 | 119 | |
jwilhelm@7095 | 120 | public static void printMemoryUsage(String label) { |
jwilhelm@7095 | 121 | MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); |
jwilhelm@7095 | 122 | float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted(); |
jwilhelm@7095 | 123 | System.out.format("[%-24s] init: %-7s, used: %-7s, comm: %-7s, freeRatio ~= %.1f%%%n", |
jwilhelm@7095 | 124 | label, |
jwilhelm@7095 | 125 | humanReadableByteCount(memusage.getInit(), true), |
jwilhelm@7095 | 126 | humanReadableByteCount(memusage.getUsed(), true), |
jwilhelm@7095 | 127 | humanReadableByteCount(memusage.getCommitted(), true), |
jwilhelm@7095 | 128 | freeratio * 100 |
jwilhelm@7095 | 129 | ); |
jwilhelm@7095 | 130 | } |
jwilhelm@7095 | 131 | } |