243

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.

Lucio Paiva
  • 19,015
  • 11
  • 82
  • 104
Steve M
  • 10,517
  • 12
  • 52
  • 63
  • 3
    With respect to free memory see http://stackoverflow.com/a/18366283/231397 (`Runtime.getRuntime().freeMemory()` as suggested in the accepted answer DOES NOT given you the amount of free memory. – Christian Fries Sep 14 '14 at 12:16

17 Answers17

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());
    }
  }
}
William Brendel
  • 31,712
  • 14
  • 72
  • 77
  • 7
    I think "Total memory currently in use by the JVM" is a little confusing. The [javadoc](http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html#totalMemory%28%29) 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 Jun 30 '12 at 00:46
  • @Dirk: I updated the wording to address your comment. Thanks! – William Brendel Jan 24 '14 at 22:46
  • @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. – William Brendel Jan 24 '14 at 22:46
  • 21
    This doesn't answer the question correctly. All that data reefers to JVM and not to the OS... – Alvaro Feb 19 '14 at 10:33
  • 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. – F_Schmidt Jun 19 '20 at 10:28
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();
        }
    }
}
travega
  • 8,284
  • 16
  • 63
  • 91
Patrick Wilkes
  • 3,401
  • 2
  • 20
  • 10
  • 10
    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. – tmarthal Feb 10 '11 at 02:47
  • 2
    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. – Raj Feb 27 '12 at 11:08
  • does **1.0** as result from `getCpuUsage` mean that the system is using all its _availableProcessors_ at 100%? – user454322 Sep 05 '12 at 09:00
  • 2
    I always get 0 as @Raj said... could you give a example of how to use that code? – dm76 Nov 28 '12 at 15:25
  • 1
    Try `((double)( processCpuTime - lastProcessCpuTime )) / ((double)( systemTime - lastSystemTime ))` – Anthony O. May 01 '13 at 10:36
  • I think they introduced similar methods in *com.sun...* bean called *getProcessCpuLoad()* and *getSystemCpuLoad()* in Java 7: https://docs.oracle.com/javase/7/docs/jre/api/management/extension/com/sun/management/OperatingSystemMXBean.html#getSystemCpuLoad() – voho Apr 03 '15 at 08:47
  • I'm using Zulu JDK and struggling to get com.sun.management.OperatingSystemMXBean class included. Moreover, if the ask is to retrieve RAM and CPU usage of the overall system, not just the JDK, this solution doesn't work – sribasu Oct 28 '22 at 00:46
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.

Aravindan R
  • 3,084
  • 1
  • 28
  • 44
Matt Cummings
  • 2,026
  • 1
  • 20
  • 22
  • is this is platform independent? Please help! – PeakGen Sep 09 '12 at 14:03
  • 2
    @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".) – Stephen C Feb 26 '13 at 06:10
  • 2
    @StephenC: Sigar is using .dll files, which makes it platform dependent. The higher level API might be in Java, it is a different story – PeakGen Feb 26 '13 at 06:49
  • @Yohan - The Runtime and MxBean APIs only report on stuff related to the current JVM. SIGAR should give you much more. – Stephen C Feb 26 '13 at 16:37
  • 1
    @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. – Jeshurun Aug 21 '13 at 15:29
  • 9
    Sigar doesn't get updated since 2010 and seems to have a bug on 64 bits systems: http://stackoverflow.com/questions/23405832/sigar-1-6-4-is-useless-exception-access-violation – Alvaro May 06 '14 at 11:07
  • 2
    And SIGAR makes the JVM crash also , (though intermittent) but i am sure you will not take this risk in production. – AKS Jun 14 '17 at 09:26
  • 1
    This ist not an answer to the question "how to get all the information from with-in Java". – Udo Apr 26 '18 at 04:50
  • @Udo - Yes. But the actual answer to that is: You can't. So it is useful to at least provide an alternative. – Stephen C Jul 17 '21 at 01:12
30

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.

Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63
dB.
  • 4,700
  • 2
  • 46
  • 51
  • 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. – Stephen C Apr 01 '11 at 11:06
  • 1
    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). – dB. May 12 '11 at 04:15
  • @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 Jun 07 '13 at 10:03
  • 1
    @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 .... – Stephen C Jun 07 '13 at 12:09
  • @StephenC does having authored the weblogic application server make me *experienced* enough? – rbp Jun 07 '13 at 15:37
  • oh and I never said that developers should not avoid native libraries. i said that libffi is safe because it is "so broadly adopted, ported, and installed" – rbp Jun 07 '13 at 15:40
  • 2
    @rhb - I'm not convinced. I see lots of hits when I google for "jvm crash libffi". – Stephen C Nov 23 '15 at 15:41
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.

Yan Khonski
  • 12,225
  • 15
  • 76
  • 114
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.

Matthew Murdoch
  • 30,874
  • 30
  • 96
  • 127
Alexandr
  • 474
  • 7
  • 13
  • 1
    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. – PeakGen Sep 09 '12 at 14:02
  • Under Linux (Ubuntu 17.10) there is not much interesting information regarding processors in the environment. – pveentjer Jul 21 '17 at 05:49
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));
}
Oleksii Kyslytsyn
  • 2,458
  • 2
  • 27
  • 43
  • OSHI has most of the information described in the other comments. It uses JNA to get it via OS native calls when possible. – Daniel Widdis Apr 13 '16 at 15:21
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.

staffan
  • 5,641
  • 3
  • 32
  • 28
  • 2
    OperatingSystemMXBean.getSystemLoadAverage() is not implemented in windows because "its too expensive" – MikeNereson Jul 14 '09 at 15:36
  • 1
    ThreadMXBean.getCurrentThreadCpuTime() only returns how long that thread has been running. Not the cpu usage percentage. – MikeNereson Jul 14 '09 at 15:37
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.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
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.

Partly Cloudy
  • 6,508
  • 3
  • 27
  • 16
4

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();
    }
}
BullyWiiPlaza
  • 17,329
  • 10
  • 113
  • 185
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());
//[...]
profesor_falken
  • 559
  • 6
  • 10
  • Nice, but it uses Guava and JNA versions that are in conflict with my needs (e.g. see [GLASSFISH-21367](https://java.net/jira/browse/GLASSFISH-21367)). – lu_ko Feb 23 '17 at 08:39
  • 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. – profesor_falken Feb 24 '17 at 22:47
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");
petro
  • 91
  • 1
  • 2
2

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

Amandeep Singh
  • 3,754
  • 8
  • 51
  • 72
2

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);
krishna Prasad
  • 3,541
  • 1
  • 34
  • 44
1

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

0

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
Priidu Neemre
  • 2,813
  • 2
  • 39
  • 40