From b10158624bd0cfe009f0fe7f2a06ee08e654766b Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Mon, 3 Jun 2024 09:26:50 +0000 Subject: [PATCH] 8332514: Allow class space size to be larger than 3GB Reviewed-by: iklam, dholmes --- src/hotspot/share/cds/metaspaceShared.cpp | 12 +- src/hotspot/share/runtime/globals.hpp | 2 +- .../CompressedClassSpaceSize.java | 170 ++++++++++++------ 3 files changed, 132 insertions(+), 52 deletions(-) diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 6213b9848f1..b0857386b10 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -1303,7 +1303,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 +1312,16 @@ 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; + 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, + 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 481115ddbe9..6f66a349595 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1399,7 +1399,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, LP64_ONLY(4*G) NOT_LP64(max_uintx)) \ \ 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 e0ec1271346..53b8e5aed4d 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 + * @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 valid_large_cds */ import jdk.test.lib.process.ProcessTools; @@ -38,59 +70,97 @@ import jdk.test.lib.process.OutputAnalyzer; 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 3GB - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:CompressedClassSpaceSize=4g", - "-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); + 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); - // 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", - "-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=trace", - "-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); + // 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); + } + break; + default: + throw new RuntimeException("invalid sub test " + args[0]); + } } }