245

I'm currently building a Java app that could end up being run on many different platforms, but primarily variants of Solaris, Linux and Windows.

Has anyone been able to successfully extract information such as the current disk space used, CPU utilisation and memory used in the underlying OS? What about just what the Java app itself is consuming?

Preferrably I'd like to get this information without using JNI.

1
  • 3
    With respect to free memory see stackoverflow.com/a/18366283/231397 (Runtime.getRuntime().freeMemory() as suggested in the accepted answer DOES NOT given you the amount of free memory. Commented Sep 14, 2014 at 12:16

17 Answers 17

209

You can get some limited memory information from the Runtime class. It really isn't exactly what you are looking for, but I thought I would provide it for the sake of completeness. Here is a small example. Edit: You can also get disk usage information from the java.io.File class. The disk space usage stuff requires Java 1.6 or higher.

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());
    }
  }
}
Sign up to request clarification or add additional context in comments.

5 Comments

I think "Total memory currently in use by the JVM" is a little confusing. The javadoc says that function returns "the total amount of memory currently available for current and future objects, measured in bytes." Sounds more like memory remaining and not in use.
@Dirk: I updated the wording to address your comment. Thanks!
@LeonardoGaldioli: I don't know the performance characteristics of these classes and methods, but I wouldn't be surprised if they weren't optimized for speed. Other answers explain how to collect certain information using JMX, which might be faster.
This doesn't answer the question correctly. All that data reefers to JVM and not to the OS...
I know that this topic is quite outdated. BUT: If you really need the amount of cpu cores, then do not use this solution. I have a dual-core CPU with two threads for each core. The JVM does not return the hardware cores, but rather the software cores/threads.
98

The java.lang.management package does give you a whole lot more info than Runtime - for example it will give you heap memory (ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()) separate from non-heap memory (ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage()).

You can also get process CPU usage (without writing your own JNI code), but you need to cast the java.lang.management.OperatingSystemMXBean to a com.sun.management.OperatingSystemMXBean. This works on Windows and Linux, I haven't tested it elsewhere.

For example ... call the get getCpuUsage() method more frequently to get more accurate readings.

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

7 Comments

To get it to compile, replace the cast OperatingSystemMXBean to com.sun.management.OperatingSystemMXBean and preface all instances of getOperatingSystemMXBean() with ManagementFactory.. You need to import all the classes appropriately.
i'm getting cpu usage as 0 for everything. i changed the cpu usage formula to cpuUsage = processCpuTime / systemTime. i'm getting a value for cpu usage which i dont understand.
does 1.0 as result from getCpuUsage mean that the system is using all its availableProcessors at 100%?
I always get 0 as @Raj said... could you give a example of how to use that code?
Try ((double)( processCpuTime - lastProcessCpuTime )) / ((double)( systemTime - lastSystemTime ))
|
43

I think the best method out there is to implement the SIGAR API by Hyperic. It works for most of the major operating systems ( darn near anything modern ) and is very easy to work with. The developer(s) are very responsive on their forum and mailing lists. I also like that it is GPL2 Apache licensed. They provide a ton of examples in Java too!

SIGAR == System Information, Gathering And Reporting tool.

9 Comments

@Yohan - Don't be lazy! You can find that out by reading the linked webpage. (And it depends on what you mean by "platform independent".)
@StephenC: Sigar is using .dll files, which makes it platform dependent. The higher level API might be in Java, it is a different story
@Artificial_Intelligence yes, but it provides libraries (written in c) for most popular platforms. It is no more platform dependant than the jvm itself. The higher level Java API should be consistent on all platforms.
Sigar doesn't get updated since 2010 and seems to have a bug on 64 bits systems: stackoverflow.com/questions/23405832/…
And SIGAR makes the JVM crash also , (though intermittent) but i am sure you will not take this risk in production.
|
31

There's a Java project that uses JNA (so no native libraries to install) and is in active development. It currently supports Linux, OSX, Windows, Solaris and FreeBSD and provides RAM, CPU, Battery and file system information.

7 Comments

No native libraries is perhaps misleading. The project uses native libraries, even if they haven't written any, and you apparently don't need to install any.
You're right. JNA uses libffi that has native components. But for all purposes, it looks like there're no native libraries (definitely none to install).
@StephenC although what you say is accurate, its misleading because its the same for rt.jar which also invokes native methods. the only reason people care about native methods is that they have to compile and/or install them, which is often often a non-trivial task. since libffi is so broadly adopted, ported, and installed, it mitigates the difficulties. so, technically you're correct, but practically, it doesn't matter.
@rbp - There's another reason people why experienced Java developers prefer to avoid native libraries. A native library that has bugs (including thread safety issues or issues with memory management) is liable to destabilize the host JVM. This is not a "it doesn't matter" issue ....
@rhb - I'm not convinced. I see lots of hits when I google for "jvm crash libffi".
|
14

For windows I went this way.

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

Here is the link with details.

3 Comments

This works on Linux too, I believe.
This works on Linux too, I confirm.
Not working anymore 2022
11

You can get some system-level information by using System.getenv(), passing the relevant environment variable name as a parameter. For example, on Windows:

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

For other operating systems the presence/absence and names of the relevant environment variables will differ.

2 Comments

These are platform dependent because variable names are different among systems. Oracle article on environment variables tells that. I am also finding a way to get system independent way.
Under Linux (Ubuntu 17.10) there is not much interesting information regarding processors in the environment.
8

Add OSHI dependency via maven:

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

Get a battery capacity left in percentage:

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

1 Comment

OSHI has most of the information described in the other comments. It uses JNA to get it via OS native calls when possible.
6

Have a look at the APIs available in the java.lang.management package. For example:

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

There are loads of other useful things in there as well.

2 Comments

OperatingSystemMXBean.getSystemLoadAverage() is not implemented in windows because "its too expensive"
ThreadMXBean.getCurrentThreadCpuTime() only returns how long that thread has been running. Not the cpu usage percentage.
6

Usually, to get low level OS information you can call OS specific commands which give you the information you want with Runtime.exec() or read files such as /proc/* in Linux.

Comments

5

CPU usage isn't straightforward -- java.lang.management via com.sun.management.OperatingSystemMXBean.getProcessCpuTime comes close (see Patrick's excellent code snippet above) but note that it only gives access to time the CPU spent in your process. it won't tell you about CPU time spent in other processes, or even CPU time spent doing system activities related to your process.

for instance i have a network-intensive java process -- it's the only thing running and the CPU is at 99% but only 55% of that is reported as "processor CPU".

don't even get me started on "load average" as it's next to useless, despite being the only cpu-related item on the MX bean. if only sun in their occasional wisdom exposed something like "getTotalCpuTime"...

for serious CPU monitoring SIGAR mentioned by Matt seems the best bet.

Comments

5

On Windows, you can run the systeminfo command and retrieves its output for instance with the following code:

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

Comments

3

If you are using Jrockit VM then here is an other way of getting VM CPU usage. Runtime bean can also give you CPU load per processor. I have used this only on Red Hat Linux to observer Tomcat performance. You have to enable JMX remote in catalina.sh for this to work.

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

Comments

3

It is still under development but you can already use jHardware

It is a simple library that scraps system data using Java. It works in both Linux and 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());
//[...]

2 Comments

Nice, but it uses Guava and JNA versions that are in conflict with my needs (e.g. see GLASSFISH-21367).
Hello, JNA has been introduced in 0.8 version of jHardware. It is only used for temperature and sensors data. If you do not need that information you can use the 0.7 version. Same thing for Guava. In that case you will have to use the 0.6.3 version.
1

Hey you can do this with java/com integration. By accessing WMI features you can get all the information.

Comments

1

One simple way which can be used to get the OS level information and I tested in my Mac which works well :

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

You can find many relevant metrics of the operating system here

Comments

1

To get the System Load average of 1 minute, 5 minutes and 15 minutes inside the java code, you can do this by executing the command cat /proc/loadavg using and interpreting it as below:

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

And to get the physical system memory by executing the command free -m and then interpreting it as below:

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

Comments

1

Not exactly what you asked for, but I'd recommend checking out ArchUtils and SystemUtils from commons-lang3. These also contain some relevant helper facilities, e.g.:

import static org.apache.commons.lang3.ArchUtils.*;
import static org.apache.commons.lang3.SystemUtils.*;

System.out.printf("OS architecture: %s\n", OS_ARCH); // OS architecture: amd64
System.out.printf("OS name: %s\n", OS_NAME);         // OS name: Linux
System.out.printf("OS version: %s\n", OS_VERSION);   // OS version: 5.18.16-200.fc36.x86_64

System.out.printf("Is Linux? - %b\n", IS_OS_LINUX);     // Is Linux? - true
System.out.printf("Is Mac? - %b\n", IS_OS_MAC);         // Is Mac? - false
System.out.printf("Is Windows? - %b\n", IS_OS_WINDOWS); // Is Windows? - false

System.out.printf("JVM name: %s\n", JAVA_VM_NAME);       // JVM name: Java HotSpot(TM) 64-Bit Server VM
System.out.printf("JVM vendor: %s\n", JAVA_VM_VENDOR);   // JVM vendor: Oracle Corporation
System.out.printf("JVM version: %s\n", JAVA_VM_VERSION); // JVM version: 11.0.12+8-LTS-237

System.out.printf("Username: %s\n", getUserName()); // Username: johndoe
System.out.printf("Hostname: %s\n", getHostName()); // Hostname: garage-pc

var processor = getProcessor();
System.out.printf("CPU arch: %s\n", processor.getArch())  // CPU arch: BIT_64
System.out.printf("CPU type: %s\n", processor.getType()); // CPU type: X86

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.