8214388: CDS dumping fails with java heap fragmentation

Force a full GC with a single thread before writing heap archive regions

Reviewed-by: sjohanss, jiangli
This commit is contained in:
Ioi Lam 2018-12-03 22:27:24 -08:00
parent ea532aa075
commit a0a108fb01
19 changed files with 489 additions and 35 deletions

@ -375,6 +375,9 @@ public:
inline int remain() {
return (int)(_end - _p);
}
int last_line_no() {
return _line_no - 1;
}
void corrupted(const char *p, const char *msg);

@ -81,6 +81,13 @@ void G1Arguments::initialize() {
vm_exit_during_initialization("The flag -XX:+UseG1GC can not be combined with -XX:ParallelGCThreads=0", NULL);
}
// When dumping the CDS archive we want to reduce fragmentation by
// triggering a full collection. To get as low fragmentation as
// possible we only use one worker thread.
if (DumpSharedSpaces) {
FLAG_SET_ERGO(uint, ParallelGCThreads, 1);
}
if (FLAG_IS_DEFAULT(G1ConcRefinementThreads)) {
FLAG_SET_ERGO(uint, G1ConcRefinementThreads, ParallelGCThreads);
}

@ -273,6 +273,69 @@ public:
};
// Should be only used at CDS dump time
class VerifyReadyForArchivingRegionClosure : public HeapRegionClosure {
bool _seen_free;
bool _has_holes;
bool _has_unexpected_holes;
bool _has_humongous;
public:
bool has_holes() {return _has_holes;}
bool has_unexpected_holes() {return _has_unexpected_holes;}
bool has_humongous() {return _has_humongous;}
VerifyReadyForArchivingRegionClosure() : HeapRegionClosure() {
_seen_free = false;
_has_holes = false;
_has_unexpected_holes = false;
_has_humongous = false;
}
virtual bool do_heap_region(HeapRegion* hr) {
const char* hole = "";
if (hr->is_free()) {
_seen_free = true;
} else {
if (_seen_free) {
_has_holes = true;
if (hr->is_humongous()) {
hole = " hole";
} else {
_has_unexpected_holes = true;
hole = " hole **** unexpected ****";
}
}
}
if (hr->is_humongous()) {
_has_humongous = true;
}
log_info(gc, region, cds)("HeapRegion " INTPTR_FORMAT " %s%s", p2i(hr->bottom()), hr->get_type_str(), hole);
return false;
}
};
// We want all used regions to be moved to the bottom-end of the heap, so we have
// a contiguous range of free regions at the top end of the heap. This way, we can
// avoid fragmentation while allocating the archive regions.
//
// Before calling this, a full GC should have been executed with a single worker thread,
// so that no old regions would be moved to the middle of the heap.
void G1HeapVerifier::verify_ready_for_archiving() {
VerifyReadyForArchivingRegionClosure cl;
G1CollectedHeap::heap()->heap_region_iterate(&cl);
if (cl.has_holes()) {
log_warning(gc, verify)("All free regions should be at the top end of the heap, but"
" we found holes. This is probably caused by (unmovable) humongous"
" allocations, and may lead to fragmentation while"
" writing archive heap memory regions.");
}
if (cl.has_humongous()) {
log_warning(gc, verify)("(Unmovable) humongous regions have been found and"
" may lead to fragmentation while"
" writing archive heap memory regions.");
}
assert(!cl.has_unexpected_holes(), "all holes should have been caused by humongous regions");
}
class VerifyArchivePointerRegionClosure: public HeapRegionClosure {
private:
G1CollectedHeap* _g1h;

@ -115,6 +115,7 @@ public:
void verify_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
void verify_dirty_young_regions() PRODUCT_RETURN;
static void verify_ready_for_archiving();
static void verify_archive_regions();
};

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2018, 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
@ -60,6 +60,9 @@ const char* GCCause::to_string(GCCause::Cause cause) {
case _wb_full_gc:
return "WhiteBox Initiated Full GC";
case _archive_time_gc:
return "Full GC for -Xshare:dump";
case _no_gc:
return "No GC";

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2018, 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
@ -52,6 +52,7 @@ class GCCause : public AllStatic {
_wb_young_gc,
_wb_conc_mark,
_wb_full_gc,
_archive_time_gc,
/* implementation independent, but reserved for GC use */
_no_gc,

@ -683,7 +683,7 @@ size_t FileMapInfo::write_archive_heap_regions(GrowableArray<MemRegion> *heap_me
int arr_len = heap_mem == NULL ? 0 : heap_mem->length();
if(arr_len > max_num_regions) {
fail_stop("Unable to write archive heap memory regions: "
"number of memory regions exceeds maximum due to fragmentation."
"number of memory regions exceeds maximum due to fragmentation. "
"Please increase java heap size "
"(current MaxHeapSize is " SIZE_FORMAT ", InitialHeapSize is " SIZE_FORMAT ").",
MaxHeapSize, InitialHeapSize);

@ -193,6 +193,8 @@ void HeapShared::archive_java_heap_objects(GrowableArray<MemRegion> *closed,
return;
}
G1HeapVerifier::verify_ready_for_archiving();
{
NoSafepointVerifier nsv;

@ -29,6 +29,7 @@
#include "classfile/classLoaderExt.hpp"
#include "classfile/dictionary.hpp"
#include "classfile/loaderConstraints.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/placeholders.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/stringTable.hpp"
@ -350,7 +351,11 @@ void MetaspaceShared::post_initialize(TRAPS) {
}
}
static GrowableArray<Handle>* _extra_interned_strings = NULL;
void MetaspaceShared::read_extra_data(const char* filename, TRAPS) {
_extra_interned_strings = new (ResourceObj::C_HEAP, mtInternal)GrowableArray<Handle>(10000, true);
HashtableTextDump reader(filename);
reader.check_version("VERSION: 1.0");
@ -358,15 +363,45 @@ void MetaspaceShared::read_extra_data(const char* filename, TRAPS) {
int utf8_length;
int prefix_type = reader.scan_prefix(&utf8_length);
ResourceMark rm(THREAD);
char* utf8_buffer = NEW_RESOURCE_ARRAY(char, utf8_length);
if (utf8_length == 0x7fffffff) {
// buf_len will overflown 32-bit value.
vm_exit_during_initialization(err_msg("string length too large: %d", utf8_length));
}
int buf_len = utf8_length+1;
char* utf8_buffer = NEW_RESOURCE_ARRAY(char, buf_len);
reader.get_utf8(utf8_buffer, utf8_length);
utf8_buffer[utf8_length] = '\0';
if (prefix_type == HashtableTextDump::SymbolPrefix) {
SymbolTable::new_symbol(utf8_buffer, utf8_length, THREAD);
SymbolTable::new_permanent_symbol(utf8_buffer, THREAD);
} else{
assert(prefix_type == HashtableTextDump::StringPrefix, "Sanity");
utf8_buffer[utf8_length] = '\0';
oop s = StringTable::intern(utf8_buffer, THREAD);
if (HAS_PENDING_EXCEPTION) {
log_warning(cds, heap)("[line %d] extra interned string allocation failed; size too large: %d",
reader.last_line_no(), utf8_length);
CLEAR_PENDING_EXCEPTION;
} else {
#if INCLUDE_G1GC
if (UseG1GC) {
typeArrayOop body = java_lang_String::value(s);
const HeapRegion* hr = G1CollectedHeap::heap()->heap_region_containing(body);
if (hr->is_humongous()) {
// Don't keep it alive, so it will be GC'ed before we dump the strings, in order
// to maximize free heap space and minimize fragmentation.
log_warning(cds, heap)("[line %d] extra interned string ignored; size too large: %d",
reader.last_line_no(), utf8_length);
continue;
}
}
#endif
// Interned strings are GC'ed if there are no references to it, so let's
// add a reference to keep this string alive.
assert(s != NULL, "must succeed");
Handle h(THREAD, s);
_extra_interned_strings->append(h);
}
}
}
}
@ -451,8 +486,6 @@ address MetaspaceShared::cds_i2i_entry_code_buffers(size_t total_size) {
return _cds_i2i_entry_code_buffers;
}
// CDS code for dumping shared archive.
// Global object for holding classes that have been loaded. Since this
// is run at a safepoint just before exit, this is the entire set of classes.
static GrowableArray<Klass*>* _global_klass_objects;
@ -1686,6 +1719,13 @@ void MetaspaceShared::preload_and_dump(TRAPS) {
link_and_cleanup_shared_classes(CATCH);
tty->print_cr("Rewriting and linking classes: done");
if (HeapShared::is_heap_object_archiving_allowed()) {
// Avoid fragmentation while archiving heap objects.
Universe::heap()->soft_ref_policy()->set_should_clear_all_soft_refs(true);
Universe::heap()->collect(GCCause::_archive_time_gc);
Universe::heap()->soft_ref_policy()->set_should_clear_all_soft_refs(false);
}
VM_PopulateDumpSharedSpace op;
VMThread::execute(&op);
}

@ -57,16 +57,12 @@ public class LotsOfClasses {
opts.addSuffix("--add-modules");
opts.addSuffix("ALL-SYSTEM");
opts.addSuffix("-Xlog:hashtables");
opts.addSuffix("-Xms500m");
opts.addSuffix("-Xmx500m");
opts.addSuffix("-Xlog:gc+region+cds");
opts.addSuffix("-Xlog:gc+region=trace");
OutputAnalyzer out = CDSTestUtils.createArchive(opts);
try {
CDSTestUtils.checkDump(out);
} catch (java.lang.RuntimeException re) {
out.shouldContain(
"number of memory regions exceeds maximum due to fragmentation");
}
CDSTestUtils.checkDump(out);
}
static void findAllClasses(ArrayList<String> list) throws Throwable {

@ -146,8 +146,11 @@ public class ArchivedIntegerCacheTest {
"-Xmx1g",
"-XX:NewSize=1g",
"-Xlog:cds+heap=info",
"-Xlog:gc+region+cds",
"-Xlog:gc+region=trace",
use_whitebox_jar);
TestCommon.checkDump(output,
"Cannot archive the sub-graph referenced from [Ljava.lang.Integer; object");
"Cannot archive the sub-graph referenced from [Ljava.lang.Integer; object",
"humongous regions have been found and may lead to fragmentation");
}
}

@ -0,0 +1,89 @@
/*
* Copyright (c) 2018, 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.
*
*/
/*
* @test
* @summary Test how CDS dumping handles the existence of humongous G1 regions.
* @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
* @requires vm.cds.archived.java.heap
* @requires vm.flavor != "minimal"
* @modules java.base/jdk.internal.misc
* jdk.jartool/sun.tools.jar
* java.management
* @build HumongousDuringDumpTransformer Hello
* @run main/othervm/timeout=240 HumongousDuringDump
*/
import jdk.test.lib.cds.CDSOptions;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class HumongousDuringDump {
public static String appClasses[] = {
"Hello",
};
public static String agentClasses[] = {
"HumongousDuringDumpTransformer",
};
public static void main(String[] args) throws Throwable {
String agentJar =
ClassFileInstaller.writeJar("HumongousDuringDumpTransformer.jar",
ClassFileInstaller.Manifest.fromSourceFile("HumongousDuringDumpTransformer.mf"),
agentClasses);
String appJar =
ClassFileInstaller.writeJar("HumongousDuringDumpApp.jar", appClasses);
String gcLog = Boolean.getBoolean("test.cds.verbose.gc") ?
"-Xlog:gc*=info,gc+region=trace,gc+alloc+region=debug" : "-showversion";
String extraArg = "-javaagent:" + agentJar;
String extraOption = "-XX:+AllowArchivingWithJavaAgent";
OutputAnalyzer out =
TestCommon.testDump(appJar, TestCommon.list("Hello"),
"-XX:+UnlockDiagnosticVMOptions", extraOption,
"-Xlog:gc+region+cds",
"-Xlog:gc+region=trace",
extraArg, "-Xmx64m", gcLog);
out.shouldContain("(Unmovable) humongous regions have been found and may lead to fragmentation");
out.shouldContain("All free regions should be at the top end of the heap, but we found holes.");
out.shouldMatch("gc,region,cds. HeapRegion .* HUM. hole");
String pattern = "gc,region,cds. HeapRegion .*hole";
out.shouldMatch(pattern);
out.shouldNotMatch(pattern + ".*unexpected");
TestCommon.run(
"-cp", appJar,
"-verbose",
"-Xmx64m",
"-XX:+PrintSharedSpaces",
"-XX:+UnlockDiagnosticVMOptions", extraOption,
gcLog,
"Hello")
.assertNormalExit();
}
}

@ -0,0 +1,112 @@
/*
* Copyright (c) 2018, 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.
*
*/
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
// This test is sensitive to -Xmx. It must be run with -xmx64m.
// Running with a different -Xmx requires changing the parameters and careful re-testing.
public class HumongousDuringDumpTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String name, Class<?> classBeingRedefined,
ProtectionDomain pd, byte[] buffer) throws IllegalClassFormatException {
if (name.equals("Hello")) {
try {
makeHumongousRegions();
} catch (Throwable t) {
array = null;
humon = null;
System.out.println("Unexpected error: " + t);
t.printStackTrace();
}
}
array = null;
return null;
}
private static Instrumentation savedInstrumentation;
public static void premain(String agentArguments, Instrumentation instrumentation) {
long xmx = Runtime.getRuntime().maxMemory();
if (xmx < 60 * 1024 * 1024 || xmx > 80 * 1024 * 1024) {
System.out.println("Running with incorrect heap size: " + xmx);
System.exit(1);
}
System.out.println("ClassFileTransformer.premain() is called");
instrumentation.addTransformer(new HumongousDuringDumpTransformer(), /*canRetransform=*/true);
savedInstrumentation = instrumentation;
}
public static Instrumentation getInstrumentation() {
return savedInstrumentation;
}
public static void agentmain(String args, Instrumentation inst) throws Exception {
premain(args, inst);
}
Object[] array;
static final int DUMMY_SIZE = 4096 - 16 - 8;
static final int HUMON_SIZE = 4 * 1024 * 1024 - 16 - 8;
static final int SKIP = 13;
byte humon[] = null;
boolean first = true;
public synchronized void makeHumongousRegions() {
if (!first) {
return;
}
System.out.println("===============================================================================");
first = false;
int total = 0;
array = new Object[100000];
System.out.println(array);
// (1) Allocate about 8MB of old objects.
for (int n=0, i=0; total < 8 * 1024 * 1024; n++) {
// Make enough allocations to cause a GC (for 64MB heap) to create
// old regions.
//
// But don't completely fill up the heap. That would cause OOM and
// may not be handled gracefully inside class transformation!
Object x = new byte[DUMMY_SIZE];
if ((n % SKIP) == 0) {
array[i++] = x;
total += DUMMY_SIZE;
}
}
System.gc();
// (2) Now allocate a humongous array. It will sit above the 8MB of old regions.
humon = new byte[HUMON_SIZE];
array = null;
System.gc();
}
}

@ -0,0 +1,5 @@
Manifest-Version: 1.0
Premain-Class: HumongousDuringDumpTransformer
Agent-Class: HumongousDuringDumpTransformer
Can-Retransform-Classes: true
Can-Redefine-Classes: true

@ -57,6 +57,7 @@ public class InvalidFileFormat {
test("OverflowPrefix.txt", "Num overflow. Corrupted at line 4");
test("UnrecognizedPrefix.txt", "Unrecognized format. Corrupted at line 5");
test("TruncatedString.txt", "Truncated. Corrupted at line 3");
test("LengthOverflow.txt", "string length too large: 2147483647");
}
private static void

@ -0,0 +1,96 @@
/*
* Copyright (c) 2018, 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.
*
*/
/*
* @test
* @summary Use a shared string allocated in a humongous G1 region.
* @comment -- the following implies that G1 is used (by command-line or by default)
* @requires vm.cds.archived.java.heap
*
* @library /test/hotspot/jtreg/runtime/appcds /test/lib
* @modules jdk.jartool/sun.tools.jar
* @build HelloString
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. SharedStringsHumongous
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import sun.hotspot.WhiteBox;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.Asserts;
public class SharedStringsHumongous {
static String sharedArchiveConfigFile = System.getProperty("user.dir") + File.separator + "SharedStringsHumongous_gen.txt";
public static void main(String[] args) throws Exception {
WhiteBox wb = WhiteBox.getWhiteBox();
try (FileOutputStream fos = new FileOutputStream(sharedArchiveConfigFile)) {
PrintWriter out = new PrintWriter(new OutputStreamWriter(fos));
out.println("VERSION: 1.0");
out.println("@SECTION: String");
out.println("31: shared_test_string_unique_14325");
int region_size = wb.g1RegionSize();
char body[] = new char[region_size + region_size / 2];
for (int i = 0; i < body.length; i++) {
body[i] = 'x';
}
Asserts.assertTrue(wb.g1IsHumongous(body));
String prefix = "generated_string (followed by " + body.length + " 'x') ";
System.out.println("G1 region size: " + region_size);
System.out.println("Using a humongous string: " + prefix);
String s = prefix + new String(body);
out.println(s.length() + ": " + s);
out.close();
}
SharedStringsUtils.run(args, SharedStringsHumongous::test);
}
public static void test(String[] args) throws Exception {
String vmOptionsPrefix[] = SharedStringsUtils.getChildVMOptionsPrefix();
String appJar = JarBuilder.build("SharedStringsHumongous", "HelloString");
OutputAnalyzer dumpOutput = TestCommon.dump(appJar, TestCommon.list("HelloString"),
TestCommon.concat(vmOptionsPrefix,
"-XX:SharedArchiveConfigFile=" + sharedArchiveConfigFile,
"-Xlog:gc+region+cds",
"-Xlog:gc+region=trace"));
TestCommon.checkDump(dumpOutput, "extra interned string ignored; size too large");
// Extra strings that are humongous are not kelp alive, so they should be GC'ed
// before dumping the string table. That means the heap should contain no
// humongous regions.
dumpOutput.shouldNotMatch("gc,region,cds. HeapRegion 0x[0-9a-f]* HUM");
OutputAnalyzer execOutput = TestCommon.exec(appJar,
TestCommon.concat(vmOptionsPrefix, "HelloString"));
TestCommon.checkExec(execOutput);
}
}

@ -29,7 +29,7 @@
* @library /test/hotspot/jtreg/runtime/appcds /test/lib
* @modules jdk.jartool/sun.tools.jar
* @build HelloString
* @run driver SharedStringsStress
* @run driver/timeout=500 SharedStringsStress
*/
import java.io.File;
import java.io.FileOutputStream;
@ -39,34 +39,56 @@ import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class SharedStringsStress {
static String sharedArchiveConfigFile = System.getProperty("user.dir") + File.separator + "SharedStringsStress_gen.txt";
public static void main(String[] args) throws Exception {
SharedStringsUtils.run(args, SharedStringsStress::test);
}
public static void test(String[] args) throws Exception {
String vmOptionsPrefix[] = SharedStringsUtils.getChildVMOptionsPrefix();
String appJar = JarBuilder.build("SharedStringsStress", "HelloString");
String sharedArchiveConfigFile = System.getProperty("user.dir") + File.separator + "SharedStringsStress_gen.txt";
try (FileOutputStream fos = new FileOutputStream(sharedArchiveConfigFile)) {
PrintWriter out = new PrintWriter(new OutputStreamWriter(fos));
out.println("VERSION: 1.0");
out.println("@SECTION: String");
out.println("31: shared_test_string_unique_14325");
for (int i=0; i<100000; i++) {
for (int i=0; i<200000; i++) {
String s = "generated_string " + i;
out.println(s.length() + ": " + s);
}
out.close();
}
OutputAnalyzer dumpOutput = TestCommon.dump(appJar, TestCommon.list("HelloString"),
TestCommon.concat(vmOptionsPrefix,
"-XX:SharedArchiveConfigFile=" + sharedArchiveConfigFile));
TestCommon.checkDump(dumpOutput);
OutputAnalyzer execOutput = TestCommon.exec(appJar,
TestCommon.concat(vmOptionsPrefix, "HelloString"));
TestCommon.checkExec(execOutput);
SharedStringsUtils.run(args, SharedStringsStress::test);
}
public static void test(String[] args) throws Exception {
String vmOptionsPrefix[] = SharedStringsUtils.getChildVMOptionsPrefix();
String appJar = JarBuilder.build("SharedStringsStress", "HelloString");
String test_cases[][] = {
// default heap size
{},
// Test for handling of heap fragmentation. With sharedArchiveConfigFile, we will dump about
// 18MB of shared objects on 64 bit VM (smaller on 32-bit).
//
// During dump time, an extra copy of these objects are allocated,
// so we need about 36MB, plus a few MB for other system data. So 64MB total heap
// should be enough.
//
// The VM should executed a full GC to maximize contiguous free space and
// avoid fragmentation.
{"-Xmx64m"},
};
for (String[] extra_opts: test_cases) {
vmOptionsPrefix = TestCommon.concat(vmOptionsPrefix, extra_opts);
OutputAnalyzer dumpOutput = TestCommon.dump(appJar, TestCommon.list("HelloString"),
TestCommon.concat(vmOptionsPrefix,
"-XX:SharedArchiveConfigFile=" + sharedArchiveConfigFile,
"-Xlog:gc+region+cds",
"-Xlog:gc+region=trace"));
TestCommon.checkDump(dumpOutput);
OutputAnalyzer execOutput = TestCommon.exec(appJar,
TestCommon.concat(vmOptionsPrefix, "HelloString"));
TestCommon.checkExec(execOutput);
}
}
}

@ -0,0 +1,10 @@
VERSION: 1.0
@SECTION: String
2147483647: s
5: cp819
31: shared_test_string_intern_12345
7: test123
@SECTION: Symbol
41 -1: (Ljava/util/Set<TE;>;Ljava/lang/Object;)V
10 -1: linkMethod
20 -1: isAlphaNumericString

@ -1,6 +1,6 @@
VERSION: 1.0
@SECTION: String
2147483647: s
40000: s
5: cp819
31: shared_test_string_intern_12345
7: test123