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

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

我希望在不使用JNI的情况下获得这些信息。


当前回答

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

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

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

其他回答

CPU使用情况并不简单——java.lang.management通过com.sun.management.OperatingSystemMXBean.getProcessCpuTime与此接近(请参阅上面Patrick的优秀代码片段),但请注意,它只允许访问CPU在进程中花费的时间。它不会告诉你在其他进程上花费的CPU时间,甚至不会告诉你在与你的进程相关的系统活动上花费的CPU时间。

例如,我有一个网络密集型的java进程——它是唯一正在运行的东西,CPU在99%,但只有55%报告为“处理器CPU”。

甚至不要让我开始“平均负载”,因为它几乎是无用的,尽管它是MX bean中唯一与cpu相关的项目。如果只有太阳在他们偶尔的智慧暴露一些像“getTotalCpuTime”…

对于严肃的CPU监控,Matt提到的SIGAR似乎是最好的选择。

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

https://github.com/oshi/oshi

通过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));
}

如果您正在使用Jrockit虚拟机,那么这里有另一种获取虚拟机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");

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