Skip to content

Commit b030467

Browse files
authored
ci: raise ASan test JVM heap to fix flaky nightly OOMs (#640)
1 parent 94a60e5 commit b030467

3 files changed

Lines changed: 39 additions & 3 deletions

File tree

build-logic/conventions/src/main/kotlin/com/datadoghq/native/config/ConfigurationPresets.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,13 @@ object ConfigurationPresets {
222222
// HeapBaseMinAddress is not accepted by JDK <= 11 (constraint violation);
223223
// those JDKs rely on the vm.mmap_rnd_bits=8 CI-level mitigation instead.
224224
if (PlatformUtils.testJvmMajorVersion() >= 12) {
225+
// HeapBaseMinAddress=64MB leaves ~1.9GB of address space below the
226+
// shadow region (0x7fff7000); 1024m keeps heap+CompressedClassSpace
227+
// well within that margin while giving forkEvery-restarted JVMs
228+
// enough headroom to avoid "Java heap space" OOMs seen in nightly CI.
225229
config.testJvmArgs.addAll(listOf(
226230
"-XX:HeapBaseMinAddress=0x4000000",
227-
"-Xmx512m",
231+
"-Xmx1024m",
228232
"-XX:CompressedClassSpaceSize=256m"
229233
))
230234
}

build-logic/conventions/src/main/kotlin/com/datadoghq/profiler/ProfilerTestPlugin.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ class ProfilerTestPlugin : Plugin<Project> {
321321
// https://github.com/eclipse-openj9/openj9/issues/23514
322322
!PlatformUtils.isTestJvmJ9()
323323
}
324-
// The ASAN test JVM is pinned to -Xmx512m (see ConfigurationPresets.kt)
324+
// The ASAN test JVM is pinned to -Xmx1024m (see ConfigurationPresets.kt)
325325
// to keep the heap below ASan's shadow-memory region. Without forking,
326326
// Gradle reuses one JVM for the whole suite, and per-test allocations
327327
// (JFR recordings, JMC object models) accumulate until it OOMs late in

ddprof-test/src/test/java/com/datadoghq/profiler/JVMAccessTest.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
import org.junit.jupiter.api.BeforeAll;
44
import org.junit.jupiter.api.Test;
55

6+
import java.lang.management.ManagementFactory;
67
import java.util.Collections;
8+
import java.util.List;
79
import java.util.concurrent.atomic.AtomicBoolean;
810
import java.util.concurrent.atomic.AtomicReference;
911

@@ -77,10 +79,40 @@ void testGetFlag() {
7779
// The test relies on the gradle test task setting the JVM flags to expected values
7880
assertEquals("build/hs_err_pid%p.log", flags.getStringFlag("ErrorFile")); // set to 'build/hs_err_pid%p.log' in the test task
7981
assertTrue(flags.getBooleanFlag("ResizeTLAB")); // set to 'true' in the test task
80-
assertEquals(512 * 1024 * 1024, flags.getIntFlag("MaxHeapSize")); // set to 512m in the test task
82+
// Derive the expected heap from this JVM's own -Xmx argument rather than hardcoding a
83+
// value, so the test stays valid regardless of what the build task passes per config.
84+
assertEquals(configuredMaxHeapBytes(), flags.getIntFlag("MaxHeapSize"));
8185
assertNotNull(flags.getStringFlag("OnError"));
8286
}
8387

88+
private static long configuredMaxHeapBytes() {
89+
// HotSpot honors the last -Xmx flag on the command line when duplicates are
90+
// present (e.g. ASan configs append a config-specific -Xmx after the
91+
// standard one), so scan from the end to find the effective value.
92+
List<String> jvmArgs = ManagementFactory.getRuntimeMXBean().getInputArguments();
93+
for (int i = jvmArgs.size() - 1; i >= 0; i--) {
94+
String arg = jvmArgs.get(i);
95+
if (arg.startsWith("-Xmx")) {
96+
return parseMemorySize(arg.substring("-Xmx".length()));
97+
}
98+
}
99+
throw new IllegalStateException("Test JVM was not launched with -Xmx: " + jvmArgs);
100+
}
101+
102+
private static long parseMemorySize(String value) {
103+
try {
104+
char unit = Character.toLowerCase(value.charAt(value.length() - 1));
105+
switch (unit) {
106+
case 'k': return Long.parseLong(value.substring(0, value.length() - 1)) * 1024L;
107+
case 'm': return Long.parseLong(value.substring(0, value.length() - 1)) * 1024L * 1024L;
108+
case 'g': return Long.parseLong(value.substring(0, value.length() - 1)) * 1024L * 1024L * 1024L;
109+
default: return Long.parseLong(value);
110+
}
111+
} catch (NumberFormatException e) {
112+
throw new IllegalArgumentException("Invalid -Xmx memory size: " + value, e);
113+
}
114+
}
115+
84116
@Test
85117
void testGetFlagMismatch() {
86118
JVMAccess.Flags flags = JVMAccess.getInstance().flags();

0 commit comments

Comments
 (0)