From 75b2a4ff77c7616cbcd0d94d2098d283eae58ee5 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Sat, 11 Dec 2021 20:58:12 +0100 Subject: [PATCH 1/5] Decrease aligned chunk size to 512 KB. --- .../oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java index 4dc96f62894c..137922523a19 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java @@ -45,7 +45,7 @@ public final class SerialAndEpsilonGCOptions { public static final RuntimeOptionKey MaximumYoungGenerationSizePercent = new NotifyGCRuntimeOptionKey<>(10, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly); @Option(help = "The size of an aligned chunk. Serial and epsilon GC only.", type = OptionType.Expert) // - public static final HostedOptionKey AlignedHeapChunkSize = new HostedOptionKey<>(1L * 1024L * 1024L, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly) { + public static final HostedOptionKey AlignedHeapChunkSize = new HostedOptionKey<>(512 * 1024L, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly) { @Override protected void onValueUpdate(EconomicMap, Object> values, Long oldValue, Long newValue) { int multiple = 4096; From 1f5731af6f3bf1e47a126e79ee16eb83a6e6ee3a Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Thu, 2 Mar 2023 12:10:15 +0100 Subject: [PATCH 2/5] Use @jdk.internal.ValueBased directly. --- substratevm/mx.substratevm/suite.py | 1 + .../src/com/oracle/svm/hosted/HostedConfiguration.java | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 2767facca013..9dbfe6526d28 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -621,6 +621,7 @@ ], "requiresConcealed" : { "java.base" : [ + "jdk.internal", "jdk.internal.event", "jdk.internal.misc", "jdk.internal.vm.annotation", diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java index 38c9362fc31c..c110cc0c8867 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java @@ -24,7 +24,6 @@ */ package com.oracle.svm.hosted; -import java.lang.annotation.Annotation; import java.nio.file.Path; import java.util.ArrayList; import java.util.HashSet; @@ -75,15 +74,13 @@ import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.meta.HostedUniverse; import com.oracle.svm.hosted.substitute.UnsafeAutomaticSubstitutionProcessor; -import com.oracle.svm.util.ReflectionUtil; +import jdk.internal.ValueBased; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaField; public class HostedConfiguration { - @SuppressWarnings("unchecked") private static final Class VALUE_BASED_ANNOTATION = // - (Class) ReflectionUtil.lookupClass(false, "jdk.internal.ValueBased"); public HostedConfiguration() { } @@ -269,7 +266,7 @@ protected void processedSynchronizedTypes(BigBang bb, HostedUniverse hUniverse, * Types that must be immutable cannot have a monitor field. */ protected static void maybeSetMonitorField(HostedUniverse hUniverse, Set immutableTypes, AnalysisType type) { - if (!type.isArray() && !immutableTypes.contains(type) && !type.isAnnotationPresent(VALUE_BASED_ANNOTATION)) { + if (!type.isArray() && !immutableTypes.contains(type) && !type.isAnnotationPresent(ValueBased.class)) { setMonitorField(hUniverse, type); } } From c65c2d0aafbfb3474bb0a7082952dcf68f6224ae Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Fri, 3 Mar 2023 10:10:49 +0100 Subject: [PATCH 3/5] Un-specify LargeArrayThreshold default. --- .../oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java index 137922523a19..27317b42499c 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java @@ -57,7 +57,7 @@ protected void onValueUpdate(EconomicMap, Object> values, Long oldV * This should be a fraction of the size of an aligned chunk, else large small arrays will not * fit in an aligned chunk. */ - @Option(help = "The size at or above which an array will be allocated in its own unaligned chunk. 0 implies (AlignedHeapChunkSize / 8). Serial and epsilon GC only.", type = OptionType.Expert) // + @Option(help = "The size at or above which an array will be allocated in its own unaligned chunk. Serial and epsilon GC only.", type = OptionType.Expert) // public static final HostedOptionKey LargeArrayThreshold = new HostedOptionKey<>(0L, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly); @Option(help = "Fill unused memory chunks with a sentinel value. Serial and epsilon GC only.", type = OptionType.Debug) // From 00c5439a070734fac8a0046c0a18ffe166a51412 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Fri, 3 Mar 2023 10:23:05 +0100 Subject: [PATCH 4/5] Add change log entry. --- substratevm/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index d71afc078b39..48efcabc0bec 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -2,6 +2,9 @@ This changelog summarizes major changes to GraalVM Native Image. +## Version 23.1.0 +* (GR-35746) Lower the default aligned chunk size from 1 MB to 512 KB for the serial and epsilon GCs, reducing memory usage and image size in many cases. + ## Version 23.0.0 * (GR-40187) Report invalid use of SVM specific classes on image class- or module-path as error. As a temporary workaround, `-H:+AllowDeprecatedBuilderClassesOnImageClasspath` allows turning the error into a warning. * (GR-41196) Provide `.debug.svm.imagebuild.*` sections that contain build options and properties used in the build of the image. From 81235decf2fce4fffc37bd1eef219ade186974c0 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Fri, 3 Mar 2023 12:51:09 +0100 Subject: [PATCH 5/5] Use current aligned chunk size in TestObjectAllocationInNewTLABEvent. --- .../TestObjectAllocationInNewTLABEvent.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestObjectAllocationInNewTLABEvent.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestObjectAllocationInNewTLABEvent.java index 7d5d69ab8705..85a0a2224c4d 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestObjectAllocationInNewTLABEvent.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestObjectAllocationInNewTLABEvent.java @@ -33,7 +33,9 @@ import org.junit.Test; import com.oracle.svm.core.NeverInline; +import com.oracle.svm.core.genscavenge.HeapParameters; import com.oracle.svm.core.jfr.JfrEvent; +import com.oracle.svm.core.util.UnsignedUtils; import jdk.jfr.consumer.RecordedClass; import jdk.jfr.consumer.RecordedEvent; @@ -41,7 +43,6 @@ public class TestObjectAllocationInNewTLABEvent extends JfrRecordingTest { private static final int K = 1024; - private static final int DEFAULT_ALIGNED_HEAP_CHUNK_SIZE = 1024 * K; @Override public String[] getTestedEvents() { @@ -50,6 +51,8 @@ public String[] getTestedEvents() { @Override protected void validateEvents(List events) throws Throwable { + final int alignedHeapChunkSize = UnsignedUtils.safeToInt(HeapParameters.getAlignedHeapChunkSize()); + boolean foundBigByteArray = false; boolean foundSmallByteArray = false; boolean foundBigCharArray = false; @@ -66,16 +69,16 @@ protected void validateEvents(List events) throws Throwable { String className = event. getValue("objectClass").getName(); // >= To account for size of reference - if (allocationSize >= 2 * DEFAULT_ALIGNED_HEAP_CHUNK_SIZE && tlabSize >= 2 * DEFAULT_ALIGNED_HEAP_CHUNK_SIZE) { + if (allocationSize >= 2 * alignedHeapChunkSize && tlabSize >= 2 * alignedHeapChunkSize) { // verify previous owner if (className.equals(char[].class.getName())) { foundBigCharArray = true; } else if (className.equals(byte[].class.getName())) { foundBigByteArray = true; } - } else if (allocationSize >= K && tlabSize == DEFAULT_ALIGNED_HEAP_CHUNK_SIZE && className.equals(byte[].class.getName())) { + } else if (allocationSize >= K && tlabSize == alignedHeapChunkSize && className.equals(byte[].class.getName())) { foundSmallByteArray = true; - } else if (tlabSize == DEFAULT_ALIGNED_HEAP_CHUNK_SIZE && className.equals(Helper.class.getName())) { + } else if (tlabSize == alignedHeapChunkSize && className.equals(Helper.class.getName())) { foundInstance = true; } } @@ -88,17 +91,19 @@ protected void validateEvents(List events) throws Throwable { @Test public void test() throws Exception { + final int alignedHeapChunkSize = UnsignedUtils.safeToInt(HeapParameters.getAlignedHeapChunkSize()); + // Allocate large arrays (always need a new TLAB). - allocateByteArray(2 * DEFAULT_ALIGNED_HEAP_CHUNK_SIZE); - allocateCharArray(DEFAULT_ALIGNED_HEAP_CHUNK_SIZE); + allocateByteArray(2 * alignedHeapChunkSize); + allocateCharArray(alignedHeapChunkSize); // Exhaust TLAB with small arrays. - for (int i = 0; i < DEFAULT_ALIGNED_HEAP_CHUNK_SIZE / K; i++) { + for (int i = 0; i < alignedHeapChunkSize / K; i++) { allocateByteArray(K); } // Exhaust TLAB with instances. - for (int i = 0; i < DEFAULT_ALIGNED_HEAP_CHUNK_SIZE; i++) { + for (int i = 0; i < alignedHeapChunkSize; i++) { allocateInstance(); } }