From 97bd2321dbba629e73cdf793a0646082b285eade Mon Sep 17 00:00:00 2001 From: tstuefe Date: Wed, 22 May 2024 13:57:19 +0200 Subject: [PATCH 1/3] JDK-8332514-Allow-class-space-size-to-be-larger-than-3GB-if-possible --- src/hotspot/share/cds/metaspaceShared.cpp | 12 ++++++- src/hotspot/share/runtime/globals.hpp | 2 +- .../CompressedClassSpaceSize.java | 32 ++++++++++++++++--- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 6213b9848f10f..e463449852f78 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -1266,6 +1266,7 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma assert(static_mapinfo->mapping_base_offset() == 0, "Must be"); size_t archive_end_offset = (dynamic_mapinfo == nullptr) ? static_mapinfo->mapping_end_offset() : dynamic_mapinfo->mapping_end_offset(); size_t archive_space_size = align_up(archive_end_offset, archive_space_alignment); + guarantee(archive_space_size < G, "weirdly large archive (" SIZE_FORMAT ")", archive_space_size); if (!Metaspace::using_class_space()) { // Get the simple case out of the way first: @@ -1303,7 +1304,7 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma "Archive base address unaligned: " PTR_FORMAT ", needs alignment: %zu.", p2i(base_address), base_address_alignment); - const size_t class_space_size = CompressedClassSpaceSize; + size_t class_space_size = CompressedClassSpaceSize; assert(CompressedClassSpaceSize > 0 && is_aligned(CompressedClassSpaceSize, class_space_alignment), "CompressedClassSpaceSize malformed: " @@ -1312,6 +1313,15 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma const size_t ccs_begin_offset = align_up(archive_space_size, class_space_alignment); const size_t gap_size = ccs_begin_offset - archive_space_size; + // Reduce class space size if it would not fit into the Klass encoding range + constexpr size_t max_encoding_range_size = 4 * G; + if ((archive_space_size + gap_size + class_space_size) > max_encoding_range_size) { + class_space_size = align_down(max_encoding_range_size - archive_space_size - gap_size, class_space_alignment); + log_info(metaspace)("CDS initialization: reducing class space size from " SIZE_FORMAT " to " SIZE_FORMAT, + CompressedClassSpaceSize, class_space_size); + FLAG_SET_ERGO(CompressedClassSpaceSize, class_space_size); + } + const size_t total_range_size = archive_space_size + gap_size + class_space_size; diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 3c05ea985b656..87b6b1b7ac7ad 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1394,7 +1394,7 @@ const int ObjectAlignmentInBytes = 8; product(size_t, CompressedClassSpaceSize, 1*G, \ "Maximum size of class area in Metaspace when compressed " \ "class pointers are used") \ - range(1*M, 3*G) \ + range(1*M, 4*G) \ \ develop(size_t, CompressedClassSpaceBaseAddress, 0, \ "Force the class space to be allocated at this address or " \ diff --git a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassSpaceSize.java b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassSpaceSize.java index e0ec12713469f..ddea0bfd4203f 100644 --- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassSpaceSize.java +++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassSpaceSize.java @@ -25,7 +25,7 @@ * @test * @bug 8022865 * @summary Tests for the -XX:CompressedClassSpaceSize command line option - * @requires vm.bits == 64 & vm.opt.final.UseCompressedOops == true + * @requires vm.bits == 64 & vm.opt.final.UseCompressedOops == true & vm.cds * @requires vm.flagless * @library /test/lib * @modules java.base/jdk.internal.misc @@ -56,20 +56,42 @@ public static void main(String[] args) throws Exception { .shouldHaveExitValue(1); - // Maximum size is 3GB - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:CompressedClassSpaceSize=4g", + // Maximum size is 4GB + long max_class_space_size = 4L * 1024 * 1024 * 1024; + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:CompressedClassSpaceSize=" + max_class_space_size + 1, "-version"); output = new OutputAnalyzer(pb.start()); output.shouldContain("outside the allowed range") .shouldHaveExitValue(1); + // Without CDS, we should get 4G + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:CompressedClassSpaceSize=" + max_class_space_size, + "-Xshare:off", "-Xlog:metaspace*", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldMatch("Compressed class space mapped at: 0x\\w+-0x\\w+, reserved size: " + max_class_space_size) + .shouldHaveExitValue(0); + + // With CDS, class space should fill whatever the CDS archive leaves us (modulo alignment) + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:CompressedClassSpaceSize=" + max_class_space_size, + "-Xshare:on", "-Xlog:metaspace*", "-version"); + { + output = new OutputAnalyzer(pb.start()); + long real_size = Long.parseLong( + output.firstMatch("reducing class space size from " + max_class_space_size + " to (\\d+)", 1)); + if (real_size < max_class_space_size * 0.75) { + output.reportDiagnosticSummary(); + throw new RuntimeException("Class space size too small?"); + } + output.shouldMatch("Compressed class space mapped at: 0x\\w+-0x\\w+, reserved size: " + real_size) + .shouldHaveExitValue(0); + } // Make sure the minimum size is set correctly and printed // (Note: ccs size are rounded up to the next larger root chunk boundary (16m). // Note that this is **reserved** size and does not affect rss. pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockDiagnosticVMOptions", "-XX:CompressedClassSpaceSize=1m", - "-Xlog:gc+metaspace=trace", + "-Xlog:gc+metaspace", "-version"); output = new OutputAnalyzer(pb.start()); output.shouldMatch("Compressed class space.*16777216") @@ -79,7 +101,7 @@ public static void main(String[] args) throws Exception { // Make sure the maximum size is set correctly and printed pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockDiagnosticVMOptions", "-XX:CompressedClassSpaceSize=3g", - "-Xlog:gc+metaspace=trace", + "-Xlog:gc+metaspace", "-version"); output = new OutputAnalyzer(pb.start()); output.shouldMatch("Compressed class space.*3221225472") From ba013f2f37aed0e6fac5e75fc0b5dcdf03d85c1b Mon Sep 17 00:00:00 2001 From: tstuefe Date: Wed, 22 May 2024 19:35:47 +0200 Subject: [PATCH 2/3] fix 32-bit (why is this not a 64-bit only option) --- src/hotspot/share/runtime/globals.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 87b6b1b7ac7ad..61b247518e979 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1394,7 +1394,7 @@ const int ObjectAlignmentInBytes = 8; product(size_t, CompressedClassSpaceSize, 1*G, \ "Maximum size of class area in Metaspace when compressed " \ "class pointers are used") \ - range(1*M, 4*G) \ + range(1*M, LP64_ONLY(4*G) NOT_LP64(max_uintx)) \ \ develop(size_t, CompressedClassSpaceBaseAddress, 0, \ "Force the class space to be allocated at this address or " \ From 2d33ad477c96d53d646db04eff39e24dd3e947a1 Mon Sep 17 00:00:00 2001 From: tstuefe Date: Mon, 27 May 2024 07:07:09 +0200 Subject: [PATCH 3/3] Remarks Ioi --- src/hotspot/share/cds/metaspaceShared.cpp | 2 +- .../CompressedClassSpaceSize.java | 188 +++++++++++------- 2 files changed, 119 insertions(+), 71 deletions(-) diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index e463449852f78..b0857386b10df 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -1266,7 +1266,6 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma assert(static_mapinfo->mapping_base_offset() == 0, "Must be"); size_t archive_end_offset = (dynamic_mapinfo == nullptr) ? static_mapinfo->mapping_end_offset() : dynamic_mapinfo->mapping_end_offset(); size_t archive_space_size = align_up(archive_end_offset, archive_space_alignment); - guarantee(archive_space_size < G, "weirdly large archive (" SIZE_FORMAT ")", archive_space_size); if (!Metaspace::using_class_space()) { // Get the simple case out of the way first: @@ -1315,6 +1314,7 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma // Reduce class space size if it would not fit into the Klass encoding range constexpr size_t max_encoding_range_size = 4 * G; + guarantee(archive_space_size < max_encoding_range_size - class_space_alignment, "Archive too large"); if ((archive_space_size + gap_size + class_space_size) > max_encoding_range_size) { class_space_size = align_down(max_encoding_range_size - archive_space_size - gap_size, class_space_alignment); log_info(metaspace)("CDS initialization: reducing class space size from " SIZE_FORMAT " to " SIZE_FORMAT, diff --git a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassSpaceSize.java b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassSpaceSize.java index ddea0bfd4203f..53b8e5aed4dec 100644 --- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassSpaceSize.java +++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassSpaceSize.java @@ -22,15 +22,47 @@ */ /* - * @test + * @test id=invalid + * @bug 8022865 + * @summary Tests for the -XX:CompressedClassSpaceSize command line option + * @requires vm.bits == 64 & vm.opt.final.UseCompressedOops == true + * @requires vm.flagless + * @library /test/lib + * @modules java.base/jdk.internal.misc java.management + * @run driver CompressedClassSpaceSize invalid + */ + +/* + * @test id=valid_small + * @bug 8022865 + * @summary Tests for the -XX:CompressedClassSpaceSize command line option + * @requires vm.bits == 64 & vm.opt.final.UseCompressedOops == true + * @requires vm.flagless + * @library /test/lib + * @modules java.base/jdk.internal.misc java.management + * @run driver CompressedClassSpaceSize valid_small + */ + +/* + * @test id=valid_large_nocds + * @bug 8022865 + * @summary Tests for the -XX:CompressedClassSpaceSize command line option + * @requires vm.bits == 64 & vm.opt.final.UseCompressedOops == true + * @requires vm.flagless + * @library /test/lib + * @modules java.base/jdk.internal.misc java.management + * @run driver CompressedClassSpaceSize valid_large_nocds + */ + +/* + * @test id=valid_large_cds * @bug 8022865 * @summary Tests for the -XX:CompressedClassSpaceSize command line option * @requires vm.bits == 64 & vm.opt.final.UseCompressedOops == true & vm.cds * @requires vm.flagless * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @run driver CompressedClassSpaceSize + * @modules java.base/jdk.internal.misc java.management + * @run driver CompressedClassSpaceSize valid_large_cds */ import jdk.test.lib.process.ProcessTools; @@ -38,81 +70,97 @@ public class CompressedClassSpaceSize { + final static long MB = 1024 * 1024; + + final static long minAllowedClassSpaceSize = MB; + final static long minRealClassSpaceSize = 16 * MB; + final static long maxClassSpaceSize = 4096 * MB; + + // For the valid_large_cds sub test: we need to have a notion of what archive size to + // maximally expect, with a generous fudge factor to avoid having to tweak this test + // ofent. Note: today's default archives are around 16-20 MB. + final static long maxExpectedArchiveSize = 512 * MB; + public static void main(String[] args) throws Exception { ProcessBuilder pb; OutputAnalyzer output; - // Minimum size is 1MB - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:CompressedClassSpaceSize=0", - "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldContain("outside the allowed range") - .shouldHaveExitValue(1); - // Invalid size of -1 should be handled correctly - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:CompressedClassSpaceSize=-1", - "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldContain("Improperly specified VM option 'CompressedClassSpaceSize=-1'") - .shouldHaveExitValue(1); + switch (args[0]) { + case "invalid": { + // < Minimum size + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:CompressedClassSpaceSize=0", + "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("outside the allowed range") + .shouldHaveExitValue(1); + // Invalid size of -1 should be handled correctly + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:CompressedClassSpaceSize=-1", + "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Improperly specified VM option 'CompressedClassSpaceSize=-1'") + .shouldHaveExitValue(1); - // Maximum size is 4GB - long max_class_space_size = 4L * 1024 * 1024 * 1024; - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:CompressedClassSpaceSize=" + max_class_space_size + 1, - "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldContain("outside the allowed range") - .shouldHaveExitValue(1); + // > Maximum size + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:CompressedClassSpaceSize=" + maxClassSpaceSize + 1, + "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("outside the allowed range") + .shouldHaveExitValue(1); - // Without CDS, we should get 4G - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:CompressedClassSpaceSize=" + max_class_space_size, - "-Xshare:off", "-Xlog:metaspace*", "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldMatch("Compressed class space mapped at: 0x\\w+-0x\\w+, reserved size: " + max_class_space_size) - .shouldHaveExitValue(0); + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:-UseCompressedClassPointers", + "-XX:CompressedClassSpaceSize=" + minAllowedClassSpaceSize, + "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Setting CompressedClassSpaceSize has no effect when compressed class pointers are not used") + .shouldHaveExitValue(0); + } + break; + case "valid_small": { + // Make sure the minimum size is set correctly and printed + // (Note: ccs size are rounded up to the next larger root chunk boundary (16m). + // Note that this is **reserved** size and does not affect rss. + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockDiagnosticVMOptions", + "-XX:CompressedClassSpaceSize=" + minAllowedClassSpaceSize, + "-Xlog:gc+metaspace", + "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldMatch("Compressed class space.*" + minRealClassSpaceSize) + .shouldHaveExitValue(0); + } + break; + case "valid_large_nocds": { + // Without CDS, we should get 4G + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:CompressedClassSpaceSize=" + maxClassSpaceSize, + "-Xshare:off", "-Xlog:metaspace*", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldMatch("Compressed class space.*" + maxClassSpaceSize) + .shouldHaveExitValue(0); + } + break; + case "valid_large_cds": { + // Create archive + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:SharedArchiveFile=./abc.jsa", "-Xshare:dump", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); - // With CDS, class space should fill whatever the CDS archive leaves us (modulo alignment) - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:CompressedClassSpaceSize=" + max_class_space_size, - "-Xshare:on", "-Xlog:metaspace*", "-version"); - { - output = new OutputAnalyzer(pb.start()); - long real_size = Long.parseLong( - output.firstMatch("reducing class space size from " + max_class_space_size + " to (\\d+)", 1)); - if (real_size < max_class_space_size * 0.75) { - output.reportDiagnosticSummary(); - throw new RuntimeException("Class space size too small?"); + // With CDS, class space should fill whatever the CDS archive leaves us (modulo alignment) + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:CompressedClassSpaceSize=" + maxClassSpaceSize, + "-XX:SharedArchiveFile=./abc.jsa", "-Xshare:on", "-Xlog:metaspace*", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + long reducedSize = Long.parseLong( + output.firstMatch("reducing class space size from " + maxClassSpaceSize + " to (\\d+)", 1)); + if (reducedSize < (maxClassSpaceSize - maxExpectedArchiveSize)) { + output.reportDiagnosticSummary(); + throw new RuntimeException("Class space size too small?"); + } + output.shouldMatch("Compressed class space.*" + reducedSize); } - output.shouldMatch("Compressed class space mapped at: 0x\\w+-0x\\w+, reserved size: " + real_size) - .shouldHaveExitValue(0); + break; + default: + throw new RuntimeException("invalid sub test " + args[0]); } - - // Make sure the minimum size is set correctly and printed - // (Note: ccs size are rounded up to the next larger root chunk boundary (16m). - // Note that this is **reserved** size and does not affect rss. - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockDiagnosticVMOptions", - "-XX:CompressedClassSpaceSize=1m", - "-Xlog:gc+metaspace", - "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldMatch("Compressed class space.*16777216") - .shouldHaveExitValue(0); - - - // Make sure the maximum size is set correctly and printed - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UnlockDiagnosticVMOptions", - "-XX:CompressedClassSpaceSize=3g", - "-Xlog:gc+metaspace", - "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldMatch("Compressed class space.*3221225472") - .shouldHaveExitValue(0); - - - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:-UseCompressedClassPointers", - "-XX:CompressedClassSpaceSize=1m", - "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldContain("Setting CompressedClassSpaceSize has no effect when compressed class pointers are not used") - .shouldHaveExitValue(0); } }