8292541: [Metrics] Reported memory limit may exceed physical machine memory

Reviewed-by: stuefe, sgehwolf
This commit is contained in:
Jonathan Dowland 2022-08-26 16:22:14 +00:00 committed by Severin Gehwolf
parent c74b6d4552
commit 9a0d1e7ce8
3 changed files with 52 additions and 16 deletions
src/java.base/linux
classes/jdk/internal/platform
native/libjava
test/hotspot/jtreg/containers/docker

@ -121,7 +121,13 @@ public class CgroupMetrics implements Metrics {
@Override
public long getMemoryLimit() {
return subsystem.getMemoryLimit();
long subsMem = subsystem.getMemoryLimit();
// Catch the cgroup memory limit exceeding host physical memory.
// Treat this as unlimited.
if (subsMem >= getTotalMemorySize0()) {
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
}
return subsMem;
}
@Override
@ -178,5 +184,6 @@ public class CgroupMetrics implements Metrics {
}
private static native boolean isUseContainerSupport();
private static native long getTotalMemorySize0();
}

@ -22,6 +22,7 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <unistd.h>
#include "jni.h"
#include "jvm.h"
@ -33,3 +34,10 @@ Java_jdk_internal_platform_CgroupMetrics_isUseContainerSupport(JNIEnv *env, jcla
{
return JVM_IsUseContainerSupport();
}
JNIEXPORT jlong JNICALL
Java_jdk_internal_platform_CgroupMetrics_getTotalMemorySize0
(JNIEnv *env, jclass ignored)
{
return sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
}

@ -47,6 +47,13 @@ import static jdk.test.lib.Asserts.assertNotNull;
public class TestMemoryAwareness {
private static final String imageName = Common.imageName("memory");
private static String getHostMaxMemory() throws Exception {
DockerRunOptions opts = Common.newOpts(imageName);
String goodMem = Common.run(opts).firstMatch("total physical memory: (\\d+)", 1);
assertNotNull(goodMem, "no match for 'total physical memory' in trace output");
return goodMem;
}
public static void main(String[] args) throws Exception {
if (!DockerTestUtils.canTestDocker()) {
return;
@ -79,7 +86,10 @@ public class TestMemoryAwareness {
"1G", Integer.toString(((int) Math.pow(2, 20)) * 1024),
"1500M", Integer.toString(((int) Math.pow(2, 20)) * (1500 - 1024))
);
testContainerMemExceedsPhysical();
final String hostMaxMem = getHostMaxMemory();
testOperatingSystemMXBeanIgnoresMemLimitExceedingPhysicalMemory(hostMaxMem);
testMetricsIgnoresMemLimitExceedingPhysicalMemory(hostMaxMem);
testContainerMemExceedsPhysical(hostMaxMem);
} finally {
if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) {
DockerTestUtils.removeDockerImage(imageName);
@ -102,24 +112,16 @@ public class TestMemoryAwareness {
// JDK-8292083
// Ensure that Java ignores container memory limit values above the host's physical memory.
private static void testContainerMemExceedsPhysical()
private static void testContainerMemExceedsPhysical(final String hostMaxMem)
throws Exception {
Common.logNewTestCase("container memory limit exceeds physical memory");
DockerRunOptions opts = Common.newOpts(imageName);
// first run: establish physical memory in test environment and derive
// a bad value one power of ten larger
String goodMem = Common.run(opts).firstMatch("total physical memory: (\\d+)", 1);
assertNotNull(goodMem, "no match for 'total physical memory' in trace output");
String badMem = goodMem + "0";
// second run: set a container memory limit to the bad value
opts = Common.newOpts(imageName)
String badMem = hostMaxMem + "0";
// set a container memory limit to the bad value
DockerRunOptions opts = Common.newOpts(imageName)
.addDockerOpts("--memory", badMem);
Common.run(opts)
.shouldMatch("container memory limit (ignored: " + badMem + "|unlimited: -1), using host value " + goodMem);
.shouldMatch("container memory limit (ignored: " + badMem + "|unlimited: -1), using host value " + hostMaxMem);
}
@ -200,4 +202,23 @@ public class TestMemoryAwareness {
}
}
// JDK-8292541: Ensure OperatingSystemMXBean ignores container memory limits above the host's physical memory.
private static void testOperatingSystemMXBeanIgnoresMemLimitExceedingPhysicalMemory(final String hostMaxMem)
throws Exception {
String badMem = hostMaxMem + "0";
testOperatingSystemMXBeanAwareness(badMem, hostMaxMem, badMem, hostMaxMem);
}
// JDK-8292541: Ensure Metrics ignores container memory limits above the host's physical memory.
private static void testMetricsIgnoresMemLimitExceedingPhysicalMemory(final String hostMaxMem)
throws Exception {
Common.logNewTestCase("Metrics ignore container memory limit exceeding physical memory");
String badMem = hostMaxMem + "0";
DockerRunOptions opts = Common.newOpts(imageName)
.addJavaOpts("-XshowSettings:system")
.addDockerOpts("--memory", badMem);
DockerTestUtils.dockerRunJava(opts).shouldMatch("Memory Limit: Unlimited");
}
}