Issue
My JDK version is OpenJDK 11. My class File is jmx.Main.class
Here are my code.
package jmx;
import java.lang.management.ManagementFactory;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
public class Main {
public static void main(String[] args) throws InstanceNotFoundException, AttributeNotFoundException, MalformedObjectNameException, ReflectionException, MBeanException {
/* Total number of processors or cores available to the JVM */
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
Object attribute = mBeanServer.getAttribute(new ObjectName("java.lang","type","OperatingSystem"), "TotalPhysicalMemorySize");
Object attribute2 = mBeanServer.getAttribute(new ObjectName("java.lang","type","OperatingSystem"), "FreePhysicalMemorySize");
System.out.println("Total memory: "+ Long.parseLong(attribute.toString()) / 1024 +"MB");
System.out.println("Free memory: "+ Long.parseLong(attribute2.toString()) / 1024 +"MB");
}
}
It works fine when it runs in IDE. I want to use a custom jre. Then I use jdeps
to analyze dependencies. The result is:
Main.class -> java.base
Main.class -> java.management
jmx -> java.io java.base
jmx -> java.lang java.base
jmx -> java.lang.invoke java.base
jmx -> java.lang.management java.management
jmx -> javax.management java.management
So I think java.base
and java.management
is the dependency modules.
Then I use jlink
to generate my custom jre.
jlink --module-path "C:\Program Files\Java\jdk-11.0.6\jmods" --add-modules java.base,java.management --output jre11
Before using my custom jre, I had run my code in cmd windows. It works fine.
Then I run the code in my jre. The code can't run and I got an error:
javax.management.AttributeNotFoundException: No such attribute: TotalPhysicalMemorySize
So I think the reason is that some dependency modules is missing. I run jlink
to generate a whole module jre. When I use the whole module jre, the code runs correctly again.
How can I get the real dependency modules? or It's a JDK's bug?
Solution
Before JDK 9, the type com.sun.management.OperatingSystemMXBean
was an undocumented extension of java.lang.management.OperatingSystemMXBean
. So it was reasonable to use a reflective attribute query like getAttribute(new ObjectName("java.lang","type","OperatingSystem"), "TotalPhysicalMemorySize")
which does not create a dependency to nonstandard APIs.
The advantage is also the disadvantage. When there is no dependency, a tool to analyse dependencies can’t detect a dependency.
When you add the module jdk.management
, the extension will be available. Being part of a documented module also implies that when you are willing to accept a permanent dependency to the module, you can use the extended OperatingSystemMXBean
directly.
import com.sun.management.OperatingSystemMXBean;
import java.lang.management.ManagementFactory;
public class OSMX {
public static void main(String[] args) {
OperatingSystemMXBean osBean
= ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class);
System.out.println("Total memory: "
+ osBean.getTotalPhysicalMemorySize() / (1024*1024) +"MB");
System.out.println("Free memory: "
+ osBean.getFreePhysicalMemorySize() / (1024*1024) +"MB");
}
}
Then, jdeps
will report the dependency to jdk.management
correctly.
Answered By - Holger
Answer Checked By - Cary Denson (JavaFixing Admin)