test/gc/g1/TestShrinkDefragmentedHeap.java

Mon, 06 Nov 2017 16:51:47 +0800

author
aoqi
date
Mon, 06 Nov 2017 16:51:47 +0800
changeset 7997
6cbff0651f1a
parent 7337
7a6313074325
permissions
-rw-r--r--

[Code Reorganization] remove trailing whitespace to pass jcheck test

     1 /*
     2  * Copyright (c) 2014, 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  */
    24 /**
    25  * @test TestShrinkDefragmentedHeap
    26  * @bug 8038423
    27  * @summary Verify that heap shrinks after GC in the presence of fragmentation due to humongous objects
    28  *     1. allocate small objects mixed with humongous ones
    29  *        "ssssHssssHssssHssssHssssHssssHssssH"
    30  *     2. release all allocated object except the last humongous one
    31  *        "..................................H"
    32  *     3. invoke gc and check that memory returned to the system (amount of committed memory got down)
    33  *
    34  * @library /testlibrary
    35  */
    36 import java.lang.management.ManagementFactory;
    37 import java.lang.management.MemoryUsage;
    38 import java.util.ArrayList;
    39 import java.util.List;
    40 import sun.management.ManagementFactoryHelper;
    41 import static com.oracle.java.testlibrary.Asserts.*;
    42 import com.oracle.java.testlibrary.ProcessTools;
    43 import com.oracle.java.testlibrary.OutputAnalyzer;
    45 public class TestShrinkDefragmentedHeap {
    46     // Since we store all the small objects, they become old and old regions are also allocated at the bottom of the heap
    47     // together with humongous regions. So if there are a lot of old regions in the lower part of the heap,
    48     // the humongous regions will be allocated in the upper part of the heap anyway.
    49     // To avoid this the Eden needs to be big enough to fit all the small objects.
    50     private static final int INITIAL_HEAP_SIZE  = 200 * 1024 * 1024;
    51     private static final int MINIMAL_YOUNG_SIZE = 190 * 1024 * 1024;
    52     private static final int REGION_SIZE        = 1 * 1024 * 1024;
    54     public static void main(String[] args) throws Exception, Throwable {
    55         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
    56                 "-XX:InitialHeapSize=" + INITIAL_HEAP_SIZE,
    57                 "-Xmn" + MINIMAL_YOUNG_SIZE,
    58                 "-XX:MinHeapFreeRatio=10",
    59                 "-XX:MaxHeapFreeRatio=11",
    60                 "-XX:+UseG1GC",
    61                 "-XX:G1HeapRegionSize=" + REGION_SIZE,
    62                 "-XX:-ExplicitGCInvokesConcurrent",
    63                 "-verbose:gc",
    64                 GCTest.class.getName()
    65         );
    67         OutputAnalyzer output = ProcessTools.executeProcess(pb);
    68         output.shouldHaveExitValue(0);
    69     }
    71     static class GCTest {
    73         private static final String MIN_FREE_RATIO_FLAG_NAME = "MinHeapFreeRatio";
    74         private static final String MAX_FREE_RATIO_FLAG_NAME = "MaxHeapFreeRatio";
    75         private static final String NEW_SIZE_FLAG_NAME = "NewSize";
    77         private static final ArrayList<ArrayList<byte[]>> garbage = new ArrayList<>();
    79         private static final int SMALL_OBJS_SIZE  = 10 * 1024; // 10kB
    80         private static final int SMALL_OBJS_COUNT = MINIMAL_YOUNG_SIZE / (SMALL_OBJS_SIZE-1);
    81         private static final int ALLOCATE_COUNT = 3;
    82         // try to put all humongous object into gap between min young size and initial heap size
    83         // to avoid implicit GCs
    84         private static final int HUMONG_OBJS_SIZE = (int) Math.max(
    85                 (INITIAL_HEAP_SIZE - MINIMAL_YOUNG_SIZE) / ALLOCATE_COUNT / 4,
    86                 REGION_SIZE * 1.1
    87         );
    89         private static final long initialHeapSize = getHeapMemoryUsage().getUsed();
    91         public static void main(String[] args) throws InterruptedException {
    92             new GCTest().test();
    93         }
    95         private void test() throws InterruptedException {
    96             MemoryUsagePrinter.printMemoryUsage("init");
    98             allocate();
    99             System.gc();
   100             MemoryUsage muFull = getHeapMemoryUsage();
   101             MemoryUsagePrinter.printMemoryUsage("allocated");
   103             free();
   104             //Thread.sleep(1000); // sleep before measures due lags in JMX
   105             MemoryUsage muFree = getHeapMemoryUsage();
   106             MemoryUsagePrinter.printMemoryUsage("free");
   108             assertLessThan(muFree.getCommitted(), muFull.getCommitted(), prepareMessageCommittedIsNotLess() );
   109         }
   111         private void allocate() {
   112             System.out.format("Will allocate objects of small size = %s and humongous size = %s",
   113                     MemoryUsagePrinter.humanReadableByteCount(SMALL_OBJS_SIZE, false),
   114                     MemoryUsagePrinter.humanReadableByteCount(HUMONG_OBJS_SIZE, false)
   115             );
   117             for (int i = 0; i < ALLOCATE_COUNT; i++) {
   118                 ArrayList<byte[]> stuff = new ArrayList<>();
   119                 allocateList(stuff, SMALL_OBJS_COUNT / ALLOCATE_COUNT, SMALL_OBJS_SIZE);
   120                 garbage.add(stuff);
   122                 ArrayList<byte[]> humongousStuff = new ArrayList<>();
   123                 allocateList(humongousStuff, 4, HUMONG_OBJS_SIZE);
   124                 garbage.add(humongousStuff);
   125             }
   126         }
   128         private void free() {
   129             // do not free last one list
   130             garbage.subList(0, garbage.size() - 1).clear();
   132             // do not free last one element from last list
   133             ArrayList stuff = garbage.get(garbage.size() - 1);
   134             if (stuff.size() > 1) {
   135                 stuff.subList(0, stuff.size() - 1).clear();
   136             }
   137             System.gc();
   138         }
   140         private String prepareMessageCommittedIsNotLess() {
   141             return String.format(
   142                     "committed free heap size is not less than committed full heap size, heap hasn't been shrunk?%n"
   143                     + "%s = %s%n%s = %s",
   144                     MIN_FREE_RATIO_FLAG_NAME,
   145                     ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MIN_FREE_RATIO_FLAG_NAME).getValue(),
   146                     MAX_FREE_RATIO_FLAG_NAME,
   147                     ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MAX_FREE_RATIO_FLAG_NAME).getValue()
   148             );
   149         }
   151         private static void allocateList(List garbage, int count, int size) {
   152             for (int i = 0; i < count; i++) {
   153                 garbage.add(new byte[size]);
   154             }
   155         }
   156     }
   158     static MemoryUsage getHeapMemoryUsage() {
   159         return ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
   160     }
   162     /**
   163      * Prints memory usage to standard output
   164      */
   165     static class MemoryUsagePrinter {
   167         public static String humanReadableByteCount(long bytes, boolean si) {
   168             int unit = si ? 1000 : 1024;
   169             if (bytes < unit) {
   170                 return bytes + " B";
   171             }
   172             int exp = (int) (Math.log(bytes) / Math.log(unit));
   173             String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i");
   174             return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
   175         }
   177         public static void printMemoryUsage(String label) {
   178             MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
   179             float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted();
   180             System.out.format("[%-24s] init: %-7s, used: %-7s, comm: %-7s, freeRatio ~= %.1f%%%n",
   181                     label,
   182                     humanReadableByteCount(memusage.getInit(), false),
   183                     humanReadableByteCount(memusage.getUsed(), false),
   184                     humanReadableByteCount(memusage.getCommitted(), false),
   185                     freeratio * 100
   186             );
   187         }
   188     }
   189 }

mercurial