获取操作系统级别的系统信息


232

我目前正在构建一个Java应用程序,该应用程序最终可能在许多不同的平台上运行,但主要是Solaris,Linux和Windows的变体。

是否有人能够成功提取信息,例如当前使用的磁盘空间,CPU利用率和底层操作系统中使用的内存?Java应用程序本身正在消耗什么呢?

最好我不使用JNI来获取此信息。


3
对于空闲内存见stackoverflow.com/a/18366283/231397Runtime.getRuntime().freeMemory()如建议在公认的回答没有给你的可用内存量。
基督教薯条

Answers:


206

您可以从Runtime类中获取一些有限的内存信息。确实不是您要找的东西,但我想为完整起见会提供它。这是一个小例子。编辑:您还可以从java.io.File类获取磁盘使用情况信息。磁盘空间使用情况需要Java 1.6或更高版本。

public class Main {
  public static void main(String[] args) {
    /* Total number of processors or cores available to the JVM */
    System.out.println("Available processors (cores): " + 
        Runtime.getRuntime().availableProcessors());

    /* Total amount of free memory available to the JVM */
    System.out.println("Free memory (bytes): " + 
        Runtime.getRuntime().freeMemory());

    /* This will return Long.MAX_VALUE if there is no preset limit */
    long maxMemory = Runtime.getRuntime().maxMemory();
    /* Maximum amount of memory the JVM will attempt to use */
    System.out.println("Maximum memory (bytes): " + 
        (maxMemory == Long.MAX_VALUE ? "no limit" : maxMemory));

    /* Total memory currently available to the JVM */
    System.out.println("Total memory available to JVM (bytes): " + 
        Runtime.getRuntime().totalMemory());

    /* Get a list of all filesystem roots on this system */
    File[] roots = File.listRoots();

    /* For each filesystem root, print some info */
    for (File root : roots) {
      System.out.println("File system root: " + root.getAbsolutePath());
      System.out.println("Total space (bytes): " + root.getTotalSpace());
      System.out.println("Free space (bytes): " + root.getFreeSpace());
      System.out.println("Usable space (bytes): " + root.getUsableSpace());
    }
  }
}

7
我认为“ JVM当前正在使用的总内存”有点令人困惑。所述的Javadoc说,函数返回“的存储器的总量目前可用于当前和未来的目的,以字节为单位测量的。” 听起来更像是剩余的内存,没有使用。
德克(Dirk)2012年

@德克:我更新了措辞,以解决您的评论。谢谢!
威廉·布伦德尔2014年

@LeonardoGaldioli:我不知道这些类和方法的性能特征,但是如果不针对速度进行优化,我也不会感到惊讶。其他答案说明了如何使用JMX收集某些信息,这可能会更快。
威廉·布伦德尔2014年

15
这不能正确回答问题。所有这些数据都存放在JVM而不是OS上……
Alvaro 2014年

我知道这个话题已经过时了。但是:如果您确实需要大量的CPU核心,请不要使用此解决方案。我有一个双核CPU,每个核有两个线程。JVM不返回硬件核心,而是返回软件核心/线程。
F_Schmidt

95

与运行时相比,java.lang.management包确实为您提供了更多信息-例如,它将为您提供堆内存(ManagementFactory.getMemoryMXBean().getHeapMemoryUsage())和非堆内存()分开的信息ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage()

您也可以获取进程CPU的使用情况(而无需编写自己的JNI代码),但是您需要将强制java.lang.management.OperatingSystemMXBean转换为com.sun.management.OperatingSystemMXBean。这可以在Windows和Linux上使用,我没有在其他地方进行过测试。

例如,...更频繁地调用get getCpuUsage()方法以获得更准确的读数。

public class PerformanceMonitor { 
    private int  availableProcessors = getOperatingSystemMXBean().getAvailableProcessors();
    private long lastSystemTime      = 0;
    private long lastProcessCpuTime  = 0;

    public synchronized double getCpuUsage()
    {
        if ( lastSystemTime == 0 )
        {
            baselineCounters();
            return;
        }

        long systemTime     = System.nanoTime();
        long processCpuTime = 0;

        if ( getOperatingSystemMXBean() instanceof OperatingSystemMXBean )
        {
            processCpuTime = ( (OperatingSystemMXBean) getOperatingSystemMXBean() ).getProcessCpuTime();
        }

        double cpuUsage = (double) ( processCpuTime - lastProcessCpuTime ) / ( systemTime - lastSystemTime );

        lastSystemTime     = systemTime;
        lastProcessCpuTime = processCpuTime;

        return cpuUsage / availableProcessors;
    }

    private void baselineCounters()
    {
        lastSystemTime = System.nanoTime();

        if ( getOperatingSystemMXBean() instanceof OperatingSystemMXBean )
        {
            lastProcessCpuTime = ( (OperatingSystemMXBean) getOperatingSystemMXBean() ).getProcessCpuTime();
        }
    }
}

10
为了得到它来编译,更换投OperatingSystemMXBeancom.sun.management.OperatingSystemMXBean和序言的所有实例getOperatingSystemMXBean()ManagementFactory.。您需要适当地导入所有类。
tmarthal

2
我将cpu的使用情况设为0。我将cpu用法公式更改为cpuUsage = processCpuTime / systemTime。我正在获取我不了解的CPU使用价值。
拉吉2012年

确实1.0如从结果getCpuUsage意味着该系统是使用其所有availableProcessors在100%?
2012年

2
我总是得到0,就像@Raj所说的那样……您能举一个使用该代码的示例吗?
dm76

1
试试((double)( processCpuTime - lastProcessCpuTime )) / ((double)( systemTime - lastSystemTime ))
AnthonyO。13年

43

我认为最好的方法是通过Hyperic实现SIGAR API。它适用于大多数主要操作系统(几乎是任何现代操作系统),并且非常易于使用。开发人员对他们的论坛和邮件列表的响应非常迅速。我还喜欢它是GPL2 Apache许可的。他们也提供了很多Java示例!

SIGAR ==系统信息,收集和报告工具。


2
@Yohan-别偷懒!您可以通过阅读链接的网页找到答案。(这取决于您所说的“平台独立”的意思。)
Stephen C

2
@StephenC:Sigar正在使用.dll文件,这使其依赖于平台。更高级别的API可能是用Java编写的,这是一个不同的故事
Lemon Juice

1
@Artificial_Intelligence是的,但是它为大多数流行的平台提供了库(用c编写)。它与平台无关,而不仅仅是jvm本身。更高级别的Java API在所有平台上都应保持一致。
Jeshurun 2013年

8
SIGAR没有得到自2010年更新,似乎有在64个系统中的错误:stackoverflow.com/questions/23405832/...
阿尔瓦罗

1
并且SIGAR也会使JVM崩溃(尽管是间歇性的),但是我敢肯定您在生产中不会冒这种风险。
AKS

25

有一个Java项目使用JNA(因此无需安装本机库)并且正在积极开发中。它目前支持Linux,OSX,Windows,Solaris和FreeBSD,并提供RAM,CPU,电池和文件系统信息。


没有本地库可能会引起误解。该项目使用本机库,即使它们未编写任何库,您显然也不需要安装任何库。
Stephen C

1
你是对的。JNA使用具有本机组件的libffi。但是出于所有目的,似乎没有本地库(肯定没有要安装的库)。
dB。

@StephenC尽管您说的是正确的,但它具有误导性,因为它与rt.jar相同,后者也调用本机方法。人们关心本机方法的唯一原因是他们必须编译和/或安装它们,这通常不是一件容易的事。由于libffi如此广泛地被采用,移植和安装,因此可以减轻这些困难。因此,从技术上讲您是正确的,但实际上并不重要。
rbp

@rbp-人们还有一个原因,为什么经验丰富的 Java开发人员更喜欢避免使用本机库。具有错误(包括线程安全性问题或内存管理问题)的本机库可能会破坏主机JVM的稳定性。这不是“无关紧要”的问题....
Stephen C

@StephenC编写了weblogic应用程序服务器确实使我足够的经验吗?
rbp

13

对于Windows,我采用这种方式。

    com.sun.management.OperatingSystemMXBean os = (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();

    long physicalMemorySize = os.getTotalPhysicalMemorySize();
    long freePhysicalMemory = os.getFreePhysicalMemorySize();
    long freeSwapSize = os.getFreeSwapSpaceSize();
    long commitedVirtualMemorySize = os.getCommittedVirtualMemorySize();

这是详细信息的链接


11

您可以通过使用System.getenv()传递相关的环境变量名称作为参数来获取一些系统级信息。例如,在Windows上:

System.getenv("PROCESSOR_IDENTIFIER")
System.getenv("PROCESSOR_ARCHITECTURE")
System.getenv("PROCESSOR_ARCHITEW6432")
System.getenv("NUMBER_OF_PROCESSORS")

对于其他操作系统,相关环境变量的存在/不存在和名称将有所不同。


1
它们是平台相关的,因为变量名称在系统之间是不同的。Oracle关于环境变量的文章说明了这一点。我也在寻找一种获得系统独立方式的方法。
柠檬汁2012年

在Linux(Ubuntu 17.10)下,关于环境中的处理器的信息不多。
pveentjer '17

8

通过maven添加OSHI依赖项:

<dependency>
    <groupId>com.github.dblock</groupId>
    <artifactId>oshi-core</artifactId>
    <version>2.2</version>
</dependency>

获取剩余的电池电量百分比:

SystemInfo si = new SystemInfo();
HardwareAbstractionLayer hal = si.getHardware();
for (PowerSource pSource : hal.getPowerSources()) {
    System.out.println(String.format("%n %s @ %.1f%%", pSource.getName(), pSource.getRemainingCapacity() * 100d));
}

OSHI具有其他注释中描述的大多数信息。如果可能,它使用JNA通过OS本机调用获取它。
Daniel Widdis '16

6

看一下java.lang.management包中可用的API 。例如:

  • OperatingSystemMXBean.getSystemLoadAverage()
  • ThreadMXBean.getCurrentThreadCpuTime()
  • ThreadMXBean.getCurrentThreadUserTime()

那里还有许多其他有用的东西。


2
Windows中未实现OperatingSystemMXBean.getSystemLoadAverage(),因为“它太贵了”
MikeNereson 2009年

1
ThreadMXBean.getCurrentThreadCpuTime()仅返回该线程已运行多长时间。不是cpu使用率百分比。
MikeNereson

5

通常,要获取底层OS信息,您可以调用特定于OS的命令,这些命令通过Runtime.exec()为您提供所需的信息,或者在Linux中读取文件/ proc / *。


5

CPU的使用并不简单-通过com.sun.management.OperatingSystemMXBean.getProcessCpuTime的java.lang.management接近(请参见上面的Patrick出色的代码片段),但是请注意,它仅提供访问CPU在进程中花费的时间的权限。它不会告诉您其他进程所花费的CPU时间,甚至不会告诉您执行与您的进程相关的系统活动所花费的CPU时间。

例如,我有一个网络密集型的Java进程-它是唯一运行的进程,CPU占99%,但是据报告只有55%是“处理器CPU”。

尽管它是MX bean上唯一与CPU相关的项目,但它甚至让我从“平均负载”开始,因为它几乎没有用。如果只有太阳在他们偶尔的智慧中暴露出诸如“ getTotalCpuTime”之类的东西...

对于Matt提到的SIGAR进行认真的CPU监视,SIGAR似乎是最好的选择。


4

在上Windows,您可以运行systeminfo命令并使用以下代码获取其输出,例如:

private static class WindowsSystemInformation
{
    static String get() throws IOException
    {
        Runtime runtime = Runtime.getRuntime();
        Process process = runtime.exec("systeminfo");
        BufferedReader systemInformationReader = new BufferedReader(new InputStreamReader(process.getInputStream()));

        StringBuilder stringBuilder = new StringBuilder();
        String line;

        while ((line = systemInformationReader.readLine()) != null)
        {
            stringBuilder.append(line);
            stringBuilder.append(System.lineSeparator());
        }

        return stringBuilder.toString().trim();
    }
}

3

如果您使用的是Jrockit VM,则这是获取VM CPU使用率的另一种方法。运行时bean还可以为您提供每个处理器的CPU负载。我仅在Red Hat Linux上使用过此功能来观察Tomcat的性能。您必须在catalina.sh中启用JMX remote才能起作用。

JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://my.tomcat.host:8080/jmxrmi");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);     
MBeanServerConnection conn = jmxc.getMBeanServerConnection();       
ObjectName name = new ObjectName("oracle.jrockit.management:type=Runtime");
Double jvmCpuLoad =(Double)conn.getAttribute(name, "VMGeneratedCPULoad");

3

它仍在开发中,但您已经可以使用jHardware

这是一个简单的库,可使用Java抓取系统数据。它可以在Linux和Windows中使用。

ProcessorInfo info = HardwareInfo.getProcessorInfo();
//Get named info
System.out.println("Cache size: " + info.getCacheSize());        
System.out.println("Family: " + info.getFamily());
System.out.println("Speed (Mhz): " + info.getMhz());
//[...]

很好,但是它使用的Guava和JNA版本与我的需求相冲突(例如,参见GLASSFISH-21367)。
lu_ko

您好,JNA已在0.8版本的jHardware中引入。仅用于温度和传感器数据。如果不需要该信息,则可以使用0.7版本。番石榴也是一样。在这种情况下,您将必须使用0.6.3版本。
profesor_falken

2

一种可以用来获取操作系统级别信息的简单方法,我在Mac上进行了测试,效果很好:

 OperatingSystemMXBean osBean =
        (OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
    return osBean.getProcessCpuLoad();

您可以在此处找到许多与操作系统相关的指标


1

嘿,您可以通过java / com集成来做到这一点。通过访问WMI功能,您可以获得所有信息。


0

要在Java代码中获得平均 1分钟,5分钟和15分钟的平均系统负载,您可以通过cat /proc/loadavg使用以下命令并解释如下命令来实现:

    Runtime runtime = Runtime.getRuntime();

    BufferedReader br = new BufferedReader(
        new InputStreamReader(runtime.exec("cat /proc/loadavg").getInputStream()));

    String avgLine = br.readLine();
    System.out.println(avgLine);
    List<String> avgLineList = Arrays.asList(avgLine.split("\\s+"));
    System.out.println(avgLineList);
    System.out.println("Average load 1 minute : " + avgLineList.get(0));
    System.out.println("Average load 5 minutes : " + avgLineList.get(1));
    System.out.println("Average load 15 minutes : " + avgLineList.get(2));

并通过执行命令然后解释如下来获取物理系统内存free -m

Runtime runtime = Runtime.getRuntime();

BufferedReader br = new BufferedReader(
    new InputStreamReader(runtime.exec("free -m").getInputStream()));

String line;
String memLine = "";
int index = 0;
while ((line = br.readLine()) != null) {
  if (index == 1) {
    memLine = line;
  }
  index++;
}
//                  total        used        free      shared  buff/cache   available
//    Mem:          15933        3153        9683         310        3097       12148
//    Swap:          3814           0        3814

List<String> memInfoList = Arrays.asList(memLine.split("\\s+"));
int totalSystemMemory = Integer.parseInt(memInfoList.get(1));
int totalSystemUsedMemory = Integer.parseInt(memInfoList.get(2));
int totalSystemFreeMemory = Integer.parseInt(memInfoList.get(3));

System.out.println("Total system memory in mb: " + totalSystemMemory);
System.out.println("Total system used memory in mb: " + totalSystemUsedMemory);
System.out.println("Total system free memory in mb: "   + totalSystemFreeMemory);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.