Hi all, Apologies if this is not the most appropriate list, in which case please direct me where to go.
I've noticed a surprising result from the com.sun.management.OperatingSystemMXBean implementation when running in a containerized (specifically, using Docker on Linux) environment. The bean appears to be container-aware for processors, in that running with Docker option `--cpus 1.0` for example, on a multicore system, will cause both java.lang.Runtime#availableProcessors and java.lang.management.OperatingSystemMXBean#getAvailableProcessors / com.sun.management.OperatingSystemMXBean#getAvailableProcessors to return 1. However, the Docker option `--memory 100M` (or any other limit value) is not reflected in the value returned by com.sun.management.OperatingSystemMXBeam#getTotalPhysicalMemorySize, and instead the returned value is still the total physical memory of the host machine - of which only a small portion may actually be available to the "Operating System" of the JVM. Similarly for the methods regarding free physical memory, total swap, and free swap. I have attached a patch which adds a small reproducer to the existing MemoryAwareness test. This seems like a bug to me, since if the imposed container limit on processors as a resource is included as part of the "Operating System" resource reporting, then surely memory resources should be reported the same way. As I said, I found the current behaviour quite surprising. -- Andrew Azores Software Engineer, OpenJDK Team Red Hat
# HG changeset patch # User Andrew Azores <aazo...@redhat.com> # Date 1561037890 14400 # Thu Jun 20 09:38:10 2019 -0400 # Node ID 25d8a60c172afc57902e8655889dd47ef26b9ca2 # Parent 8d50ff464ae56ad62679b44afa705276c7aece50 [mq]: test diff --git a/test/hotspot/jtreg/containers/docker/CheckOperatingSystemMXBean.java b/test/hotspot/jtreg/containers/docker/CheckOperatingSystemMXBean.java new file mode 100644 --- /dev/null +++ b/test/hotspot/jtreg/containers/docker/CheckOperatingSystemMXBean.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.sun.management.OperatingSystemMXBean; +import java.lang.management.ManagementFactory; + +public class CheckOperatingSystemMXBean { + + public static void main(String[] args) { + System.out.println("Checking OperatingSystemMXBean"); + + OperatingSystemMXBean osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); + System.out.println(String.format("Runtime.availableProcessors: %d", Runtime.getRuntime().availableProcessors())); + System.out.println(String.format("OperatingSystemMXBean.getAvailableProcessors: %d", osBean.getAvailableProcessors())); + System.out.println(String.format("OperatingSystemMXBean.getTotalPhysicalMemorySize: %d", osBean.getTotalPhysicalMemorySize())); + System.out.println(String.format("OperatingSystemMXBean.getTotalSwapSpaceSize: %d", osBean.getTotalSwapSpaceSize())); + } + +} diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java --- a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java @@ -30,7 +30,7 @@ * @modules java.base/jdk.internal.misc * java.management * jdk.jartool/sun.tools.jar - * @build AttemptOOM sun.hotspot.WhiteBox PrintContainerInfo + * @build AttemptOOM sun.hotspot.WhiteBox PrintContainerInfo CheckOperatingSystemMXBean * @run driver ClassFileInstaller -jar whitebox.jar sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission * @run driver TestMemoryAwareness */ @@ -62,8 +62,25 @@ // Add extra 10 Mb to allocator limit, to be sure to cause OOM testOOM("256m", 256 + 10); + testMXBeanAwareness( + "1.0", "1", + "100M", Integer.toString(((int) Math.pow(2, 20)) * 100), + "150M", Integer.toString(((int) Math.pow(2, 20)) * 150) + ); + testMXBeanAwareness( + "1.0", "1", + "128M", Integer.toString(((int) Math.pow(2, 20)) * 128), + "256M", Integer.toString(((int) Math.pow(2, 20)) * 256) + ); + testMXBeanAwareness( + "1.0", "1", + "1G", Integer.toString(((int) Math.pow(2, 20)) * 1024), + "1500M", Integer.toString(((int) Math.pow(2, 20)) * 1500) + ); } finally { - DockerTestUtils.removeDockerImage(imageName); + if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) { + DockerTestUtils.removeDockerImage(imageName); + } } } @@ -109,4 +126,24 @@ .shouldContain("java.lang.OutOfMemoryError"); } + private static void testMXBeanAwareness(String cpuAllocation, String expectedCpus, String memoryAllocation, + String expectedMemory, String swapAllocation, String expectedSwap) throws Exception { + Common.logNewTestCase("Check OperatingSystemMXBean"); + + DockerRunOptions opts = Common.newOpts(imageName, "CheckOperatingSystemMXBean") + .addDockerOpts( + "--cpus", cpuAllocation, + "--memory", memoryAllocation, + "--memory-swap", swapAllocation + ); + + DockerTestUtils.dockerRunJava(opts) + .shouldHaveExitValue(0) + .shouldContain("Checking OperatingSystemMXBean") + .shouldContain("Runtime.availableProcessors: " + expectedCpus) + .shouldContain("OperatingSystemMXBean.getAvailableProcessors: " + expectedCpus) + .shouldContain("OperatingSystemMXBean.getTotalPhysicalMemorySize: " + expectedMemory) + .shouldContain("OperatingSystemMXBean.getTotalSwapSpaceSize: " + expectedSwap); + } + }