Wie überwache ich die CPU-, Speicher- und Festplattennutzung des Computers in Java?

180

Ich möchte die folgenden Systeminformationen in Java überwachen:

  • Aktuelle CPU-Auslastung ** (Prozent)
  • Verfügbarer Speicher * (frei / insgesamt)
  • Verfügbarer Speicherplatz (frei / insgesamt)

    * Beachten Sie, dass ich den Gesamtspeicher meine, der dem gesamten System zur Verfügung steht, nicht nur der JVM.

Ich suche nach einer plattformübergreifenden Lösung (Linux, Mac und Windows), die nicht auf meinem eigenen Code basiert, der externe Programme aufruft oder JNI verwendet. Obwohl dies praktikable Optionen sind, würde ich es vorziehen, den betriebssystemspezifischen Code nicht selbst zu pflegen, wenn jemand bereits eine bessere Lösung hat.

Wenn es eine kostenlose Bibliothek gibt, die dies zuverlässig und plattformübergreifend tut, wäre das großartig (selbst wenn sie externe Anrufe tätigt oder nativen Code selbst verwendet).

Anregungen werden sehr geschätzt.

Zur Verdeutlichung möchte ich die aktuelle CPU-Auslastung für das gesamte System ermitteln, nicht nur für die Java-Prozesse.

Die SIGAR-API bietet alle Funktionen, die ich suche, in einem Paket, sodass sie die bisher beste Antwort auf meine Frage ist. Da es jedoch unter der GPL lizenziert ist, kann ich es nicht für meinen ursprünglichen Zweck verwenden (ein geschlossenes, kommerzielles Produkt). Es ist möglich, dass Hyperic SIGAR für die kommerzielle Nutzung lizenziert, aber ich habe es nicht untersucht. Für meine GPL-Projekte werde ich in Zukunft definitiv SIGAR in Betracht ziehen.

Für meine aktuellen Bedürfnisse neige ich zu Folgendem:

  • Für die CPU-Auslastung OperatingSystemMXBean.getSystemLoadAverage() / OperatingSystemMXBean.getAvailableProcessors()(Lastdurchschnitt pro CPU)
  • Für die Erinnerung OperatingSystemMXBean.getTotalPhysicalMemorySize()undOperatingSystemMXBean.getFreePhysicalMemorySize()
  • Für Speicherplatz File.getTotalSpace()undFile.getUsableSpace()

Einschränkungen:

Die getSystemLoadAverage()Abfragemethoden und Speicherplatz sind nur unter Java 6 verfügbar. Außerdem sind einige JMX-Funktionen möglicherweise nicht für alle Plattformen verfügbar (dh es wurde berichtet, dass dies der Fall istgetSystemLoadAverage() unter Windows -1 zurückgegeben wird).

Obwohl ursprünglich unter GPL lizenziert, wurde es in Apache 2.0 geändert , das im Allgemeinen für kommerzielle Closed-Source-Produkte verwendet werden kann.

David Crow
quelle
Zur Verdeutlichung erhalten Sie über die Sigar-API Systeminformationen. Wenn Sie JVM-Informationen wünschen, verwenden Sie JMX.
Matt Cummings
Wenn SIGAR unter der GPL steht, können Sie es nicht verwenden. Es bedeutet lediglich, dass Sie sich an die Autoren wenden und eine alternative Lizenzierung anfordern müssen. Autoren akzeptieren häufig gerne eine geringe Gebühr und erlauben kommerzielle Lizenzen.
Alec Thomas
7
Seit Version 1.6.4 verwendet SIGAR die Apache-Lizenz.
Soundlink
Wissen Sie, wie Sie die Last für jeden einzelnen Prozessor ermitteln können?
zcaudate

Antworten:

67

In Anlehnung an das, was ich in diesem Beitrag erwähnt habe . Ich empfehle Ihnen, die SIGAR-API zu verwenden . Ich verwende die SIGAR-API in einer meiner eigenen Anwendungen und sie ist großartig. Sie werden feststellen, dass es stabil, gut unterstützt und voller nützlicher Beispiele ist. Es ist Open Source mit einer GPL 2 Apache 2.0-Lizenz. Hör zu. Ich habe das Gefühl, es wird Ihren Bedürfnissen entsprechen.

Mit Java und der Sigar-API können Sie Speicher, CPU, Festplatte, Lastdurchschnitt, Informationen und Metriken zur Netzwerkschnittstelle, Informationen zur Prozesstabelle, Routeninformationen usw. abrufen.

Matt Cummings
quelle
14
Seien Sie vorsichtig, wenn Sie Sigar verwenden, es gibt Probleme auf x64-Computern ... stackoverflow.com/questions/23405832/… und es scheint, dass die Bibliothek seit 2010 nicht aktualisiert wird
Alvaro
56

Das Folgende bringt Ihnen angeblich CPU und RAM. Weitere Informationen finden Sie unter ManagementFactory .

import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

private static void printUsage() {
  OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();
  for (Method method : operatingSystemMXBean.getClass().getDeclaredMethods()) {
    method.setAccessible(true);
    if (method.getName().startsWith("get")
        && Modifier.isPublic(method.getModifiers())) {
            Object value;
        try {
            value = method.invoke(operatingSystemMXBean);
        } catch (Exception e) {
            value = e;
        } // try
        System.out.println(method.getName() + " = " + value);
    } // if
  } // for
}
Eugene Yokota
quelle
3
Beispielausgabe für den obigen Code. Dieser Code funktioniert unter Java 1.5. getCommittedVirtualMemorySize = 28622848 getFreePhysicalMemorySize = 228462592 getFreeSwapSpaceSize = 1129848832 getProcessCpuTime = 390625000 getTotalPhysicalMemorySize = 2147483647 getTotalSwapSpaceSize = 4294967295
blak3r
AFAIK getProcessCpuTime = 390625000 gibt nur an, wie lange dieser Thread ausgeführt wurde. Das ist nicht wirklich nützlich, um die Prozessorauslastung zu bestimmen
MikeNereson
2
Ich bin mir nicht sicher, ob es tatsächlich zuverlässig ist. Unter Windows XP mit 4 GB physischem Speicher werden nur 2 GB gemeldet (getestet mit Java 6 und Java 7). Die gesamte Swap-Größe ist ebenfalls falsch.
Emmanuel Bourg
4
@EmmanuelBourg Nur um für Leute zu dokumentieren, die dieses Thema sehen, gibt es einen Fehler, der damit zusammenhängt.
Sérgio Michels
2
Diese Methode hat bis Java 9 hervorragend funktioniert. Jetzt wird aufgrund des neuen Java-Frameworks für die Zugriffsprüfung eine java.lang.reflect.InaccessibleObjectException ausgelöst.
Thor Lancaster
40

In JDK 1.7 können Sie die CPU- und Speicherauslastung des Systems über abrufen com.sun.management.OperatingSystemMXBean. Das ist anders als java.lang.management.OperatingSystemMXBean.

long    getCommittedVirtualMemorySize()
Returns the amount of virtual memory that is guaranteed to be available to the running process in bytes, or -1 if this operation is not supported.

long    getFreePhysicalMemorySize()
Returns the amount of free physical memory in bytes.

long    getFreeSwapSpaceSize()
Returns the amount of free swap space in bytes.

double  getProcessCpuLoad()
Returns the "recent cpu usage" for the Java Virtual Machine process.

long    getProcessCpuTime()
Returns the CPU time used by the process on which the Java virtual machine is running in nanoseconds.

double  getSystemCpuLoad()
Returns the "recent cpu usage" for the whole system.

long    getTotalPhysicalMemorySize()
Returns the total amount of physical memory in bytes.

long    getTotalSwapSpaceSize()
Returns the total amount of swap space in bytes.
Gp2you
quelle
5
Scheint, als wäre dies ein Hit und Miss. Erhalten von -1 für CPU-Last auf FreeBSD 10 und OpenJDK 8.
cen
Überprüfen Sie diese Frage stackoverflow.com/q/19781087/1206998 . Es heißt, dass es ein paar Sekunden dauert, um effektiv zu sein. (Anmerkung: Ich habe es nicht versucht)
Juh_
25

Dies funktioniert für mich perfekt ohne externe API, nur native Java versteckte Funktion :)

import com.sun.management.OperatingSystemMXBean;
...
OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(
                OperatingSystemMXBean.class);
// What % CPU load this current JVM is taking, from 0.0-1.0
System.out.println(osBean.getProcessCpuLoad());

// What % load the overall system is at, from 0.0-1.0
System.out.println(osBean.getSystemCpuLoad());
bizzr3
quelle
Ich finde das ehrlich gesagt die beste Antwort, funktioniert unter Linux, also bin ich ein glücklicher Kerl.
ArsenArsen
1
Gibt es einen Hinweis, warum ein zweiter Aufruf 0.0 anzeigt? Auf OpenJDK v8.
Vorburger
Vergessen Sie nicht: "import java.lang.management.ManagementFactory;"
Bernd
1
getProcessCpuLoad und getSystemCpuLoad geben -1 von mir zurück. Ich benutze JDK 1.8
Burak Akyıldız
Es gibt keine Methode, um die Anzahl der Threads zu ermitteln? Ich frage mich nur warum?
Djangofan
16

Schauen Sie sich diesen sehr detaillierten Artikel an: http://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarking#UsingaSuninternalclasstogetJVMCPUtime

Um den Prozentsatz der verwendeten CPU zu ermitteln, benötigen Sie lediglich einige einfache Berechnungen:

MBeanServerConnection mbsc = ManagementFactory.getPlatformMBeanServer();

OperatingSystemMXBean osMBean = ManagementFactory.newPlatformMXBeanProxy(
mbsc, ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME, OperatingSystemMXBean.class);

long nanoBefore = System.nanoTime();
long cpuBefore = osMBean.getProcessCpuTime();

// Call an expensive task, or sleep if you are monitoring a remote process

long cpuAfter = osMBean.getProcessCpuTime();
long nanoAfter = System.nanoTime();

long percent;
if (nanoAfter > nanoBefore)
 percent = ((cpuAfter-cpuBefore)*100L)/
   (nanoAfter-nanoBefore);
else percent = 0;

System.out.println("Cpu usage: "+percent+"%");

Hinweis: Sie müssen importieren com.sun.management.OperatingSystemMXBeanund nicht java.lang.management.OperatingSystemMXBean.

ludovicc
quelle
Das ist eine wirklich gute Antwort. Alle anderen Techniken liefern wirklich seltsame und unzuverlässige Ergebnisse, aber diese mit einer nachlaufenden Mittelung hat für mich wie ein Zauber gewirkt.
Fractaly
Wenn die CPU-Zeit höher ist als die verstrichene Zeit (ich bekomme über 100%), liegt das nur am Multithreading oder wie kann man das verstehen?
Lukas Hanacek
8

Wenn Sie über Java 6 verfügen, können Sie für den Speicherplatz die Methoden getTotalSpace und getFreeSpace für File verwenden. Wenn Sie nicht mit Java 6 arbeiten, können Sie meines Erachtens Apache Commons IO verwenden , um einen Teil des Weges dorthin zu finden.

Ich kenne keine plattformübergreifende Methode, um die CPU- oder Speicherauslastung zu ermitteln, fürchte ich.

Matt Sheppard
quelle
6

Vieles davon ist bereits über JMX verfügbar. In Java 5 ist JMX integriert und enthält einen JMX-Konsolen-Viewer mit dem JDK.

Sie können JMX verwenden, um manuell zu überwachen, oder JMX-Befehle von Java aus aufrufen, wenn Sie diese Informationen in Ihrer eigenen Laufzeit benötigen.

Jason Cohen
quelle
4
/* YOU CAN TRY THIS TOO */

import java.io.File;
 import java.lang.management.ManagementFactory;
// import java.lang.management.OperatingSystemMXBean;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.management.RuntimeMXBean;
 import java.io.*;
 import java.net.*;
 import java.util.*;
 import java.io.LineNumberReader;
 import java.lang.management.ManagementFactory;
import com.sun.management.OperatingSystemMXBean;
import java.lang.management.ManagementFactory;
import java.util.Random;



 public class Pragati
 {

     public static void printUsage(Runtime runtime)
     {
     long total, free, used;
     int mb = 1024*1024;

     total = runtime.totalMemory();
     free = runtime.freeMemory();
     used = total - free;
     System.out.println("\nTotal Memory: " + total / mb + "MB");
     System.out.println(" Memory Used: " + used / mb + "MB");
     System.out.println(" Memory Free: " + free / mb + "MB");
     System.out.println("Percent Used: " + ((double)used/(double)total)*100 + "%");
     System.out.println("Percent Free: " + ((double)free/(double)total)*100 + "%");
    }
    public static void log(Object message)
         {
            System.out.println(message);
         }

        public static int calcCPU(long cpuStartTime, long elapsedStartTime, int cpuCount)
        {
             long end = System.nanoTime();
             long totalAvailCPUTime = cpuCount * (end-elapsedStartTime);
             long totalUsedCPUTime = ManagementFactory.getThreadMXBean().getCurrentThreadCpuTime()-cpuStartTime;
             //log("Total CPU Time:" + totalUsedCPUTime + " ns.");
             //log("Total Avail CPU Time:" + totalAvailCPUTime + " ns.");
             float per = ((float)totalUsedCPUTime*100)/(float)totalAvailCPUTime;
             log( per);
             return (int)per;
        }

        static boolean isPrime(int n)
        {
     // 2 is the smallest prime
            if (n <= 2)
            {
                return n == 2;
            }
     // even numbers other than 2 are not prime
            if (n % 2 == 0)
            {
                return false;
            }
     // check odd divisors from 3
     // to the square root of n
         for (int i = 3, end = (int)Math.sqrt(n); i <= end; i += 2)
         {
            if (n % i == 0)
         {
         return false;
        }
        }
 return true;
}
    public static void main(String [] args)
    {
            int mb = 1024*1024;
            int gb = 1024*1024*1024;
             /* PHYSICAL MEMORY USAGE */
             System.out.println("\n**** Sizes in Mega Bytes ****\n");
            com.sun.management.OperatingSystemMXBean operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
            //RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
            //operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
            com.sun.management.OperatingSystemMXBean os = (com.sun.management.OperatingSystemMXBean)
            java.lang.management.ManagementFactory.getOperatingSystemMXBean();
            long physicalMemorySize = os.getTotalPhysicalMemorySize();
            System.out.println("PHYSICAL MEMORY DETAILS \n");
            System.out.println("total physical memory : " + physicalMemorySize / mb + "MB ");
            long physicalfreeMemorySize = os.getFreePhysicalMemorySize();
            System.out.println("total free physical memory : " + physicalfreeMemorySize / mb + "MB");
            /* DISC SPACE DETAILS */
            File diskPartition = new File("C:");
            File diskPartition1 = new File("D:");
            File diskPartition2 = new File("E:");
            long totalCapacity = diskPartition.getTotalSpace() / gb;
            long totalCapacity1 = diskPartition1.getTotalSpace() / gb;
            double freePartitionSpace = diskPartition.getFreeSpace() / gb;
            double freePartitionSpace1 = diskPartition1.getFreeSpace() / gb;
            double freePartitionSpace2 = diskPartition2.getFreeSpace() / gb;
            double usablePatitionSpace = diskPartition.getUsableSpace() / gb;
            System.out.println("\n**** Sizes in Giga Bytes ****\n");
            System.out.println("DISC SPACE DETAILS \n");
            //System.out.println("Total C partition size : " + totalCapacity + "GB");
            //System.out.println("Usable Space : " + usablePatitionSpace + "GB");
            System.out.println("Free Space in drive C: : " + freePartitionSpace + "GB");
            System.out.println("Free Space in drive D:  : " + freePartitionSpace1 + "GB");
            System.out.println("Free Space in drive E: " + freePartitionSpace2 + "GB");
            if(freePartitionSpace <= totalCapacity%10 || freePartitionSpace1 <= totalCapacity1%10)
            {
                System.out.println(" !!!alert!!!!");
            }
            else
                System.out.println("no alert");

            Runtime runtime;
            byte[] bytes;
            System.out.println("\n \n**MEMORY DETAILS  ** \n");
            // Print initial memory usage.
            runtime = Runtime.getRuntime();
            printUsage(runtime);

            // Allocate a 1 Megabyte and print memory usage
            bytes = new byte[1024*1024];
            printUsage(runtime);

            bytes = null;
            // Invoke garbage collector to reclaim the allocated memory.
            runtime.gc();

            // Wait 5 seconds to give garbage collector a chance to run
            try {
            Thread.sleep(5000);
            } catch(InterruptedException e) {
            e.printStackTrace();
            return;
            }

            // Total memory will probably be the same as the second printUsage call,
            // but the free memory should be about 1 Megabyte larger if garbage
            // collection kicked in.
            printUsage(runtime);
            for(int i = 0; i < 30; i++)
                     {
                         long start = System.nanoTime();
                        // log(start);
                        //number of available processors;
                         int cpuCount = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors();
                         Random random = new Random(start);
                         int seed = Math.abs(random.nextInt());
                         log("\n \n CPU USAGE DETAILS \n\n");
                         log("Starting Test with " + cpuCount + " CPUs and random number:" + seed);
                         int primes = 10000;
                         //
                         long startCPUTime = ManagementFactory.getThreadMXBean().getCurrentThreadCpuTime();
                         start = System.nanoTime();
                         while(primes != 0)
                         {
                            if(isPrime(seed))
                            {
                                primes--;
                            }
                            seed++;

                        }
                         float cpuPercent = calcCPU(startCPUTime, start, cpuCount);
                         log("CPU USAGE : " + cpuPercent + " % ");


                         try
                         {
                             Thread.sleep(1000);
                         }
                         catch (InterruptedException e) {}
        }

            try
            {
                Thread.sleep(500);
            }`enter code here`
            catch (Exception ignored) { }
        }
    }
Pragati
quelle
4

Der folgende Code ist nur Linux (möglicherweise Unix), funktioniert jedoch in einem realen Projekt.

    private double getAverageValueByLinux() throws InterruptedException {
    try {

        long delay = 50;
        List<Double> listValues = new ArrayList<Double>();
        for (int i = 0; i < 100; i++) {
            long cput1 = getCpuT();
            Thread.sleep(delay);
            long cput2 = getCpuT();
            double cpuproc = (1000d * (cput2 - cput1)) / (double) delay;
            listValues.add(cpuproc);
        }
        listValues.remove(0);
        listValues.remove(listValues.size() - 1);
        double sum = 0.0;
        for (Double double1 : listValues) {
            sum += double1;
        }
        return sum / listValues.size();
    } catch (Exception e) {
        e.printStackTrace();
        return 0;
    }

}

private long getCpuT throws FileNotFoundException, IOException {
    BufferedReader reader = new BufferedReader(new FileReader("/proc/stat"));
    String line = reader.readLine();
    Pattern pattern = Pattern.compile("\\D+(\\d+)\\D+(\\d+)\\D+(\\d+)\\D+(\\d+)")
    Matcher m = pattern.matcher(line);

    long cpuUser = 0;
    long cpuSystem = 0;
    if (m.find()) {
        cpuUser = Long.parseLong(m.group(1));
        cpuSystem = Long.parseLong(m.group(3));
    }
    return cpuUser + cpuSystem;
}
Charis Theo
quelle
1
Dies ist eigentlich das, wonach ich gesucht habe, aber dem Code fehlt das REGEX-Muster zum Finden der CPU-Informationen aus dem / proc / stat
Donal Tobin
Was ist das Muster?
HCarrasko
3

Erstellen Sie eine Batch-Datei "Pc.bat" als, geben Sieperf -sc 1 "\ mukit \ processor (_Total) \ %% Processor Time" ein.

Sie können die Klasse MProcess verwenden,

/ *
 * Md. Mukit Hasan
 * CSE-JU, 35
 ** / Java importieren . io . *;

MProzessor der öffentlichen Klasse {

public MProcessor() { String s; try { Process ps = Runtime.getRuntime().exec("Pc.bat"); BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream())); while((s = br.readLine()) != null) { System.out.println(s); } } catch( Exception ex ) { System.out.println(ex.toString()); } }

}}

Nach einigen String-Manipulationen erhalten Sie dann die CPU-Auslastung. Sie können den gleichen Prozess für andere Aufgaben verwenden.

- Mukit Hasan

Md. Mukit Hasan
quelle
1
Für mich (Win XP) war die richtige Befehlszeile: typeperf "\processor(_total)\% processor time"Wenn Sie sie in eine Batch-Datei einfügen, verwenden Sie %% anstelle von%. Ich habe technet.microsoft.com/en-us/library/bb490960.aspx verwendet .
Tutejszy