Skip to content

Commit

Permalink
8292541: [Metrics] Reported memory limit may exceed physical machine …
Browse files Browse the repository at this point in the history
…memory

Backport-of: 9a0d1e7ce86368cdcade713a9e220604f7d77ecf
  • Loading branch information
Jonathan Dowland committed Sep 6, 2022
1 parent f75b74d commit 131eab6
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 16 deletions.
Expand Up @@ -121,7 +121,13 @@ public long getMemoryFailCount() {

@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
Expand Down Expand Up @@ -178,5 +184,6 @@ public static Metrics getInstance() {
}

private static native boolean isUseContainerSupport();
private static native long getTotalMemorySize0();

}
8 changes: 8 additions & 0 deletions src/java.base/linux/native/libjava/CgroupMetrics.c
Expand Up @@ -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"
Expand All @@ -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);
}
51 changes: 36 additions & 15 deletions test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java
Expand Up @@ -47,6 +47,13 @@
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;
Expand Down Expand Up @@ -79,7 +86,10 @@ public static void main(String[] args) throws Exception {
"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);
Expand All @@ -102,24 +112,16 @@ private static void testMemoryLimit(String valueToSet, String expectedTraceValue

// 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);
}


Expand Down Expand Up @@ -197,4 +199,23 @@ private static void testOperatingSystemMXBeanAwareness(String memoryAllocation,
}
}


// 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");
}
}

1 comment on commit 131eab6

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.