Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/test/gc/g1/TestShrinkDefragmentedHeap.java
32284 views
/*1* Copyright (c) 2014, 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*/2223/**24* @test TestShrinkDefragmentedHeap25* @bug 803842326* @summary Verify that heap shrinks after GC in the presence of fragmentation due to humongous objects27* 1. allocate small objects mixed with humongous ones28* "ssssHssssHssssHssssHssssHssssHssssH"29* 2. release all allocated object except the last humongous one30* "..................................H"31* 3. invoke gc and check that memory returned to the system (amount of committed memory got down)32*33* @library /testlibrary34*/35import java.lang.management.ManagementFactory;36import java.lang.management.MemoryUsage;37import java.util.ArrayList;38import java.util.List;39import sun.management.ManagementFactoryHelper;40import static com.oracle.java.testlibrary.Asserts.*;41import com.oracle.java.testlibrary.ProcessTools;42import com.oracle.java.testlibrary.OutputAnalyzer;4344public class TestShrinkDefragmentedHeap {45// Since we store all the small objects, they become old and old regions are also allocated at the bottom of the heap46// together with humongous regions. So if there are a lot of old regions in the lower part of the heap,47// the humongous regions will be allocated in the upper part of the heap anyway.48// To avoid this the Eden needs to be big enough to fit all the small objects.49private static final int INITIAL_HEAP_SIZE = 200 * 1024 * 1024;50private static final int MINIMAL_YOUNG_SIZE = 190 * 1024 * 1024;51private static final int REGION_SIZE = 1 * 1024 * 1024;5253public static void main(String[] args) throws Exception, Throwable {54ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(55"-XX:InitialHeapSize=" + INITIAL_HEAP_SIZE,56"-Xmn" + MINIMAL_YOUNG_SIZE,57"-XX:MinHeapFreeRatio=10",58"-XX:MaxHeapFreeRatio=11",59"-XX:+UseG1GC",60"-XX:G1HeapRegionSize=" + REGION_SIZE,61"-XX:-ExplicitGCInvokesConcurrent",62"-verbose:gc",63GCTest.class.getName()64);6566OutputAnalyzer output = ProcessTools.executeProcess(pb);67output.shouldHaveExitValue(0);68}6970static class GCTest {7172private static final String MIN_FREE_RATIO_FLAG_NAME = "MinHeapFreeRatio";73private static final String MAX_FREE_RATIO_FLAG_NAME = "MaxHeapFreeRatio";74private static final String NEW_SIZE_FLAG_NAME = "NewSize";7576private static final ArrayList<ArrayList<byte[]>> garbage = new ArrayList<>();7778private static final int SMALL_OBJS_SIZE = 10 * 1024; // 10kB79private static final int SMALL_OBJS_COUNT = MINIMAL_YOUNG_SIZE / (SMALL_OBJS_SIZE-1);80private static final int ALLOCATE_COUNT = 3;81// try to put all humongous object into gap between min young size and initial heap size82// to avoid implicit GCs83private static final int HUMONG_OBJS_SIZE = (int) Math.max(84(INITIAL_HEAP_SIZE - MINIMAL_YOUNG_SIZE) / ALLOCATE_COUNT / 4,85REGION_SIZE * 1.186);8788private static final long initialHeapSize = getHeapMemoryUsage().getUsed();8990public static void main(String[] args) throws InterruptedException {91new GCTest().test();92}9394private void test() throws InterruptedException {95MemoryUsagePrinter.printMemoryUsage("init");9697allocate();98System.gc();99MemoryUsage muFull = getHeapMemoryUsage();100MemoryUsagePrinter.printMemoryUsage("allocated");101102free();103//Thread.sleep(1000); // sleep before measures due lags in JMX104MemoryUsage muFree = getHeapMemoryUsage();105MemoryUsagePrinter.printMemoryUsage("free");106107assertLessThan(muFree.getCommitted(), muFull.getCommitted(), prepareMessageCommittedIsNotLess() );108}109110private void allocate() {111System.out.format("Will allocate objects of small size = %s and humongous size = %s",112MemoryUsagePrinter.humanReadableByteCount(SMALL_OBJS_SIZE, false),113MemoryUsagePrinter.humanReadableByteCount(HUMONG_OBJS_SIZE, false)114);115116for (int i = 0; i < ALLOCATE_COUNT; i++) {117ArrayList<byte[]> stuff = new ArrayList<>();118allocateList(stuff, SMALL_OBJS_COUNT / ALLOCATE_COUNT, SMALL_OBJS_SIZE);119garbage.add(stuff);120121ArrayList<byte[]> humongousStuff = new ArrayList<>();122allocateList(humongousStuff, 4, HUMONG_OBJS_SIZE);123garbage.add(humongousStuff);124}125}126127private void free() {128// do not free last one list129garbage.subList(0, garbage.size() - 1).clear();130131// do not free last one element from last list132ArrayList stuff = garbage.get(garbage.size() - 1);133if (stuff.size() > 1) {134stuff.subList(0, stuff.size() - 1).clear();135}136System.gc();137}138139private String prepareMessageCommittedIsNotLess() {140return String.format(141"committed free heap size is not less than committed full heap size, heap hasn't been shrunk?%n"142+ "%s = %s%n%s = %s",143MIN_FREE_RATIO_FLAG_NAME,144ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MIN_FREE_RATIO_FLAG_NAME).getValue(),145MAX_FREE_RATIO_FLAG_NAME,146ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MAX_FREE_RATIO_FLAG_NAME).getValue()147);148}149150private static void allocateList(List garbage, int count, int size) {151for (int i = 0; i < count; i++) {152garbage.add(new byte[size]);153}154}155}156157static MemoryUsage getHeapMemoryUsage() {158return ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();159}160161/**162* Prints memory usage to standard output163*/164static class MemoryUsagePrinter {165166public static String humanReadableByteCount(long bytes, boolean si) {167int unit = si ? 1000 : 1024;168if (bytes < unit) {169return bytes + " B";170}171int exp = (int) (Math.log(bytes) / Math.log(unit));172String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i");173return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);174}175176public static void printMemoryUsage(String label) {177MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();178float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted();179System.out.format("[%-24s] init: %-7s, used: %-7s, comm: %-7s, freeRatio ~= %.1f%%%n",180label,181humanReadableByteCount(memusage.getInit(), false),182humanReadableByteCount(memusage.getUsed(), false),183humanReadableByteCount(memusage.getCommitted(), false),184freeratio * 100185);186}187}188}189190191