Path: blob/master/test/hotspot/jtreg/gc/g1/TestShrinkDefragmentedHeap.java
40942 views
/*1* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223package gc.g1;2425/**26* @test TestShrinkDefragmentedHeap27* @bug 8038423 812959028* @summary Verify that heap shrinks after GC in the presence of fragmentation due to humongous objects29* 1. allocate small objects mixed with humongous ones30* "ssssHssssHssssHssssHssssHssssHssssH"31* 2. release all allocated object except the last humongous one32* "..................................H"33* 3. invoke gc and check that memory returned to the system (amount of committed memory got down)34*35* @library /test/lib /36* @requires vm.gc.G137* @modules java.base/jdk.internal.misc38* java.management/sun.management39* @run driver gc.g1.TestShrinkDefragmentedHeap40*/41import java.lang.management.ManagementFactory;42import java.lang.management.MemoryUsage;43import java.util.ArrayList;44import java.util.List;45import java.text.NumberFormat;46import static jdk.test.lib.Asserts.*;47import jdk.test.lib.process.OutputAnalyzer;48import jdk.test.lib.process.ProcessTools;49import com.sun.management.HotSpotDiagnosticMXBean;50import gc.testlibrary.Helpers;5152public class TestShrinkDefragmentedHeap {53// Since we store all the small objects, they become old and old regions are also allocated at the bottom of the heap54// together with humongous regions. So if there are a lot of old regions in the lower part of the heap,55// the humongous regions will be allocated in the upper part of the heap anyway.56// To avoid this the Eden needs to be big enough to fit all the small objects.57private static final int INITIAL_HEAP_SIZE = 200 * 1024 * 1024;58private static final int MINIMAL_YOUNG_SIZE = 190 * 1024 * 1024;59private static final int MAXIMUM_HEAP_SIZE = 256 * 1024 * 1024;60private static final int REGION_SIZE = 1 * 1024 * 1024;6162public static void main(String[] args) throws Exception, Throwable {63ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(64"-XX:InitialHeapSize=" + INITIAL_HEAP_SIZE,65"-Xmn" + MINIMAL_YOUNG_SIZE,66"-Xmx" + MAXIMUM_HEAP_SIZE,67"-XX:MinHeapFreeRatio=10",68"-XX:MaxHeapFreeRatio=11",69"-XX:+UseG1GC",70"-XX:G1HeapRegionSize=" + REGION_SIZE,71"-XX:-ExplicitGCInvokesConcurrent",72"-verbose:gc",73GCTest.class.getName()74);7576OutputAnalyzer output = ProcessTools.executeProcess(pb);77output.shouldHaveExitValue(0);78}7980static class GCTest {8182private static final String MIN_FREE_RATIO_FLAG_NAME = "MinHeapFreeRatio";83private static final String MAX_FREE_RATIO_FLAG_NAME = "MaxHeapFreeRatio";84private static final String NEW_SIZE_FLAG_NAME = "NewSize";8586private static final ArrayList<ArrayList<byte[]>> garbage = new ArrayList<>();8788private static final int SMALL_OBJS_SIZE = 10 * 1024; // 10kB89private static final int SMALL_OBJS_COUNT = MINIMAL_YOUNG_SIZE / (SMALL_OBJS_SIZE-1);90private static final int ALLOCATE_COUNT = 3;91// try to put all humongous object into gap between min young size and initial heap size92// to avoid implicit GCs93private static final int HUMONG_OBJS_SIZE = (int) Math.max(94(INITIAL_HEAP_SIZE - MINIMAL_YOUNG_SIZE) / ALLOCATE_COUNT / 4,95REGION_SIZE * 1.196);9798private static final long initialHeapSize = getHeapMemoryUsage().getUsed();99100public static void main(String[] args) throws InterruptedException {101new GCTest().test();102}103104private void test() throws InterruptedException {105MemoryUsagePrinter.printMemoryUsage("init");106107allocate();108System.gc();109MemoryUsage muFull = getHeapMemoryUsage();110MemoryUsagePrinter.printMemoryUsage("allocated");111112free();113//Thread.sleep(1000); // sleep before measures due lags in JMX114MemoryUsage muFree = getHeapMemoryUsage();115MemoryUsagePrinter.printMemoryUsage("free");116117assertLessThan(muFree.getCommitted(), muFull.getCommitted(), prepareMessageCommittedIsNotLess() );118}119120private void allocate() {121System.out.format("Will allocate objects of small size = %s and humongous size = %s",122MemoryUsagePrinter.NF.format(SMALL_OBJS_SIZE),123MemoryUsagePrinter.NF.format(HUMONG_OBJS_SIZE)124);125126for (int i = 0; i < ALLOCATE_COUNT; i++) {127ArrayList<byte[]> stuff = new ArrayList<>();128allocateList(stuff, SMALL_OBJS_COUNT / ALLOCATE_COUNT, SMALL_OBJS_SIZE);129garbage.add(stuff);130131ArrayList<byte[]> humongousStuff = new ArrayList<>();132allocateList(humongousStuff, 4, HUMONG_OBJS_SIZE);133garbage.add(humongousStuff);134}135}136137private void free() {138// do not free last one list139garbage.subList(0, garbage.size() - 1).clear();140141// do not free last one element from last list142ArrayList<byte[]> stuff = garbage.get(garbage.size() - 1);143if (stuff.size() > 1) {144stuff.subList(0, stuff.size() - 1).clear();145}146System.gc();147}148149private String prepareMessageCommittedIsNotLess() {150return String.format(151"committed free heap size is not less than committed full heap size, heap hasn't been shrunk?%n"152+ "%s = %s%n%s = %s",153MIN_FREE_RATIO_FLAG_NAME,154ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class)155.getVMOption(MIN_FREE_RATIO_FLAG_NAME).getValue(),156MAX_FREE_RATIO_FLAG_NAME,157ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class)158.getVMOption(MAX_FREE_RATIO_FLAG_NAME).getValue()159);160}161162private static void allocateList(List<byte[]> garbage, int count, int size) {163for (int i = 0; i < count; i++) {164garbage.add(new byte[size]);165}166}167}168169static MemoryUsage getHeapMemoryUsage() {170return ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();171}172173/**174* Prints memory usage to standard output175*/176static class MemoryUsagePrinter {177178public static final NumberFormat NF = Helpers.numberFormatter();179180public static void printMemoryUsage(String label) {181MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();182float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted();183System.out.format("[%-24s] init: %-7s, used: %-7s, comm: %-7s, freeRatio ~= %.1f%%%n",184label,185NF.format(memusage.getInit()),186NF.format(memusage.getUsed()),187NF.format(memusage.getCommitted()),188freeratio * 100189);190}191}192}193194195