1d1cd32bc3
Reviewed-by: tschatzl, aboldtch
309 lines
13 KiB
Java
309 lines
13 KiB
Java
/*
|
|
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
package gc.arguments;
|
|
|
|
/*
|
|
* @test TestMaxMinHeapFreeRatioFlags
|
|
* @summary Verify that heap size changes according to max and min heap free ratios.
|
|
* @requires vm.gc != "Z" & vm.gc != "Shenandoah"
|
|
* @library /test/lib
|
|
* @library /
|
|
* @modules java.base/jdk.internal.misc
|
|
* java.management
|
|
* @run driver/timeout=240 gc.arguments.TestMaxMinHeapFreeRatioFlags
|
|
*/
|
|
|
|
import java.util.LinkedList;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import jdk.test.lib.process.OutputAnalyzer;
|
|
import jdk.test.lib.Utils;
|
|
import jdk.internal.misc.Unsafe;
|
|
|
|
public class TestMaxMinHeapFreeRatioFlags {
|
|
|
|
public static final long M = 1024 * 1024;
|
|
public static final long MAX_HEAP_SIZE = 200 * M;
|
|
public static final long HEAP_SIZE = 10 * M;
|
|
public static final long MAX_NEW_SIZE = 20 * M;
|
|
public static final long NEW_SIZE = 5 * M;
|
|
|
|
public static void main(String args[]) throws Exception {
|
|
LinkedList<String> options = new LinkedList<>(
|
|
Arrays.asList(Utils.getFilteredTestJavaOpts("-XX:[^ ]*HeapFreeRatio","-XX:\\+ExplicitGCInvokesConcurrent"))
|
|
);
|
|
|
|
negativeTest(20, false, 10, true, options);
|
|
negativeTest(100, true, 0, false, options);
|
|
negativeTest(101, false, 50, false, options);
|
|
negativeTest(49, true, 102, true, options);
|
|
negativeTest(-1, false, 50, false, options);
|
|
negativeTest(50, true, -1, true, options);
|
|
|
|
positiveTest(10, false, 90, false, true, options);
|
|
positiveTest(10, true, 80, false, true, options);
|
|
positiveTest(20, false, 70, true, true, options);
|
|
positiveTest(25, true, 65, true, true, options);
|
|
positiveTest(40, false, 50, false, true, options);
|
|
}
|
|
|
|
/**
|
|
* Verify that heap size will be changed to conform
|
|
* min and max heap free ratios.
|
|
*
|
|
* @param minRatio value of MinHeapFreeRatio option
|
|
* @param useXminf used Xminf option instead of MinHeapFreeRatio
|
|
* @param maxRatio value of MaxHeapFreeRatio option
|
|
* @param useXmaxf used Xmaxf option instead of MaxHeapFreeRatio
|
|
* @param options additional options for JVM
|
|
*/
|
|
public static void positiveTest(int minRatio, boolean useXminf,
|
|
int maxRatio, boolean useXmaxf, boolean shrinkHeapInSteps,
|
|
LinkedList<String> options) throws Exception {
|
|
|
|
LinkedList<String> vmOptions = new LinkedList<>(options);
|
|
Collections.addAll(vmOptions,
|
|
(useXminf ? "-Xminf" + minRatio / 100.0 : "-XX:MinHeapFreeRatio=" + minRatio),
|
|
(useXmaxf ? "-Xmaxf" + maxRatio / 100.0 : "-XX:MaxHeapFreeRatio=" + maxRatio),
|
|
"-Xmx" + MAX_HEAP_SIZE,
|
|
"-Xms" + HEAP_SIZE,
|
|
"--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED",
|
|
"-XX:NewSize=" + NEW_SIZE,
|
|
"-XX:MaxNewSize=" + MAX_NEW_SIZE,
|
|
"-XX:" + (shrinkHeapInSteps ? '+' : '-') + "ShrinkHeapInSteps",
|
|
RatioVerifier.class.getName(),
|
|
Integer.toString(minRatio),
|
|
Integer.toString(maxRatio),
|
|
Boolean.toString(shrinkHeapInSteps)
|
|
);
|
|
|
|
OutputAnalyzer analyzer = GCArguments.executeLimitedTestJava(vmOptions);
|
|
analyzer.shouldHaveExitValue(0);
|
|
}
|
|
|
|
/**
|
|
* Verify that VM will fail to start with specified ratios.
|
|
*
|
|
* @param minRatio value of MinHeapFreeRatio option
|
|
* @param useXminf used Xminf option instead of MinHeapFreeRatio
|
|
* @param maxRatio value of MaxHeapFreeRatio option
|
|
* @param useXmaxf used Xmaxf option instead of MaxHeapFreeRatio
|
|
* @param options additional options for JVM
|
|
*/
|
|
public static void negativeTest(int minRatio, boolean useXminf,
|
|
int maxRatio, boolean useXmaxf,
|
|
LinkedList<String> options) throws Exception {
|
|
|
|
LinkedList<String> vmOptions = new LinkedList<>(options);
|
|
Collections.addAll(vmOptions,
|
|
(useXminf ? "-Xminf" + minRatio / 100.0 : "-XX:MinHeapFreeRatio=" + minRatio),
|
|
(useXmaxf ? "-Xmaxf" + maxRatio / 100.0 : "-XX:MaxHeapFreeRatio=" + maxRatio),
|
|
"--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED",
|
|
"-version"
|
|
);
|
|
OutputAnalyzer analyzer = GCArguments.executeLimitedTestJava(vmOptions);
|
|
analyzer.shouldHaveExitValue(1);
|
|
analyzer.shouldContain("Error: Could not create the Java Virtual Machine.");
|
|
}
|
|
|
|
/**
|
|
* RatioVerifier will be executed in the tested VM.
|
|
* It will check that real heap usage after collection lies between MinHeapFreeRatio and MaxHeapFreeRatio.
|
|
*/
|
|
public static class RatioVerifier {
|
|
|
|
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
|
|
|
// Size of byte array that will be allocated
|
|
public static final int CHUNK_SIZE = 1024;
|
|
// Length of byte array, that will be added to "garbage" list.
|
|
public static final int ARRAY_LENGTH = CHUNK_SIZE - Unsafe.ARRAY_BYTE_BASE_OFFSET;
|
|
// Amount of tries to force heap shrinking/expansion using GC
|
|
public static final int GC_TRIES = 10;
|
|
|
|
// Value that will be added/substracted from expected min/max heap free ratio
|
|
// during memory allocation to make sure that specified limit will be exceeded.
|
|
public static final double OVERLOAD = 0.05;
|
|
// Acceptable heap free ratio limit exceedance: verification will fail if
|
|
// actual ratio is lower than expected min heap free ratio - VARIANCE or
|
|
// higher than expected max heap free ratio + VARIANCE.
|
|
public static final double VARIANCE = 0.025;
|
|
|
|
public static LinkedList<Object> garbage = new LinkedList<>();
|
|
|
|
public static void main(String args[]) throws Exception {
|
|
if (args.length != 3) {
|
|
throw new IllegalArgumentException("Expected 3 args: <minRatio> <maxRatio> <shrinkHeapInSteps>");
|
|
}
|
|
if (GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.PSOld ||
|
|
GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.G1) {
|
|
System.out.println("Test is not applicable to parallel full GCs");
|
|
return;
|
|
}
|
|
|
|
double minRatio = Integer.valueOf(args[0]) / 100.0;
|
|
double maxRatio = Integer.valueOf(args[1]) / 100.0;
|
|
boolean shrinkHeapInSteps = Boolean.valueOf(args[2]);
|
|
|
|
long maxHeapSize = getMax();
|
|
int gcTries = (shrinkHeapInSteps ? GC_TRIES : 1);
|
|
|
|
// Initial checks. This also links up everything in these helper methods,
|
|
// in case it brings more garbage.
|
|
forceGC(gcTries);
|
|
verifyRatio(minRatio, maxRatio);
|
|
|
|
// commit 0.5 of total heap size to have enough space
|
|
// to both shink and expand
|
|
while (getCommitted() < maxHeapSize / 2) {
|
|
garbage.add(new byte[ARRAY_LENGTH]);
|
|
}
|
|
|
|
forceGC(gcTries);
|
|
// Verify that current heap free ratio lies between specified limits
|
|
verifyRatio(minRatio, maxRatio);
|
|
|
|
// Estimate how much memory we have to allocate to force expansion
|
|
long memoryToFill = (long) (getCommitted() * (1 - minRatio + OVERLOAD))
|
|
- getUsed();
|
|
|
|
long previouslyCommitted = getCommitted();
|
|
|
|
while (memoryToFill > 0) {
|
|
garbage.add(new byte[CHUNK_SIZE]);
|
|
memoryToFill -= CHUNK_SIZE;
|
|
}
|
|
|
|
forceGC(gcTries);
|
|
// Verify that after memory allocation heap free ratio is still conforming specified limits
|
|
verifyRatio(minRatio, maxRatio);
|
|
// Verify that heap was actually expanded
|
|
if (previouslyCommitted >= getCommitted()) {
|
|
throw new RuntimeException("Heap was not expanded.");
|
|
}
|
|
|
|
// Estimate how much memory we have to free to force shrinking
|
|
long memoryToFree = getUsed()
|
|
- (long) (getCommitted() * (1 - maxRatio - OVERLOAD));
|
|
|
|
previouslyCommitted = getCommitted();
|
|
|
|
while (memoryToFree > 0 && garbage.size() > 0) {
|
|
garbage.remove(garbage.size() - 1);
|
|
memoryToFree -= CHUNK_SIZE;
|
|
}
|
|
|
|
forceGC(gcTries);
|
|
// Verify that heap free ratio is still conforming specified limits
|
|
verifyRatio(minRatio, maxRatio);
|
|
// Verify that heap was actually shrinked
|
|
if (previouslyCommitted <= getCommitted()) {
|
|
throw new RuntimeException("Heap was not shrinked.");
|
|
}
|
|
}
|
|
|
|
public static void forceGC(int gcTries) {
|
|
for (int i = 0; i < gcTries; i++) {
|
|
System.gc();
|
|
try {
|
|
Thread.sleep(10);
|
|
} catch (InterruptedException ie) {
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verify that heap free ratio is conforming specified limits.
|
|
* Actual heap free ratio may be very close to one of specified limits,
|
|
* but exceed for more then VARIANCE.
|
|
* Verification will also pass if actual ratio is not conforming limits,
|
|
* but it is not possible to shrink/expand heap.
|
|
*/
|
|
public static void verifyRatio(double minRatio, double maxRatio) {
|
|
double ratio = getHeapFreeRatio();
|
|
System.out.println(minRatio + " " + ratio + " " + maxRatio);
|
|
if (minRatio - ratio > VARIANCE
|
|
&& getCommitted() < getMax()) {
|
|
throw new RuntimeException("Current heap free ratio is lower than "
|
|
+ "MinHeapFreeRatio (" + ratio + " vs " + minRatio + ").");
|
|
}
|
|
if (ratio - maxRatio > VARIANCE
|
|
&& getUsed() > getInit()) {
|
|
throw new RuntimeException("Current heap free ratio is higher than "
|
|
+ "MaxHeapFreeRatio (" + ratio + " vs " + maxRatio + ").");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Obtain information about heap size.
|
|
*
|
|
* For G1 information summed up for all type of regions,
|
|
* because tested options affect overall heap sizing.
|
|
*
|
|
* For all other GCs return information only for old gen.
|
|
*/
|
|
public static long getMax() {
|
|
return HeapRegionUsageTool.getOldUsage().getMax();
|
|
}
|
|
|
|
public static long getInit() {
|
|
if (GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.G1) {
|
|
return HeapRegionUsageTool.getEdenUsage().getInit()
|
|
+ HeapRegionUsageTool.getSurvivorUsage().getInit()
|
|
+ HeapRegionUsageTool.getOldUsage().getInit();
|
|
} else {
|
|
return HeapRegionUsageTool.getOldUsage().getInit();
|
|
}
|
|
}
|
|
|
|
public static long getUsed() {
|
|
if (GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.G1) {
|
|
return HeapRegionUsageTool.getEdenUsage().getUsed()
|
|
+ HeapRegionUsageTool.getSurvivorUsage().getUsed()
|
|
+ HeapRegionUsageTool.getOldUsage().getUsed();
|
|
} else {
|
|
return HeapRegionUsageTool.getOldUsage().getUsed();
|
|
}
|
|
}
|
|
|
|
public static long getCommitted() {
|
|
if (GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.G1) {
|
|
return HeapRegionUsageTool.getEdenUsage().getCommitted()
|
|
+ HeapRegionUsageTool.getSurvivorUsage().getCommitted()
|
|
+ HeapRegionUsageTool.getOldUsage().getCommitted();
|
|
} else {
|
|
return HeapRegionUsageTool.getOldUsage().getCommitted();
|
|
}
|
|
}
|
|
|
|
public static long getFree() {
|
|
return getCommitted() - getUsed();
|
|
}
|
|
|
|
public static double getHeapFreeRatio() {
|
|
return getFree() / (double) getCommitted();
|
|
}
|
|
}
|
|
}
|