Come posso monitorare CPU, memoria e utilizzo del disco del computer in Java?


180

Vorrei monitorare le seguenti informazioni di sistema in Java:

  • Utilizzo corrente della CPU ** (percentuale)
  • Memoria disponibile * (libera / totale)
  • Spazio disponibile su disco (libero / totale)

    * Nota che intendo la memoria complessiva disponibile per l'intero sistema, non solo per la JVM.

Sto cercando una soluzione multipiattaforma (Linux, Mac e Windows) che non si basa sul mio codice per chiamare programmi esterni o usare JNI. Sebbene queste siano opzioni praticabili, preferirei non mantenere il codice specifico del sistema operativo se qualcuno ha già una soluzione migliore.

Se c'è una libreria gratuita là fuori che lo fa in modo affidabile e multipiattaforma, sarebbe fantastico (anche se effettua chiamate esterne o utilizza il codice nativo stesso).

Eventuali suggerimenti sono molto apprezzati.

Per chiarire, vorrei ottenere l'attuale utilizzo della CPU per l'intero sistema, non solo per i processi Java.

L'API SIGAR offre tutte le funzionalità che sto cercando in un pacchetto, quindi è la risposta migliore alla mia domanda finora. Tuttavia, poiché è concesso in licenza in base alla licenza GPL, non posso utilizzarlo per il mio scopo originale (un prodotto commerciale, a sorgente chiuso). È possibile che Hyperic possa concedere in licenza SIGAR per uso commerciale, ma non ci ho pensato. Per i miei progetti GPL, prenderò sicuramente in considerazione SIGAR in futuro.

Per le mie attuali esigenze, mi sto orientando verso quanto segue:

  • Per l'utilizzo della CPU, OperatingSystemMXBean.getSystemLoadAverage() / OperatingSystemMXBean.getAvailableProcessors()(carico medio per CPU)
  • Per memoria, OperatingSystemMXBean.getTotalPhysicalMemorySize()eOperatingSystemMXBean.getFreePhysicalMemorySize()
  • Per spazio su disco File.getTotalSpace()eFile.getUsableSpace()

limitazioni:

I getSystemLoadAverage()metodi di query dello spazio su disco e sono disponibili solo in Java 6. Inoltre, alcune funzionalità JMX potrebbero non essere disponibili per tutte le piattaforme (ovvero è stato segnalato che getSystemLoadAverage()restituisce -1 su Windows).

Sebbene originariamente concesso in licenza in GPL, è stato modificato in Apache 2.0 , che può essere generalmente utilizzato per prodotti commerciali chiusi.


Per chiarire, il sigar api ottiene informazioni sul sistema. Se vuoi informazioni jvm usa JMX.
Matt Cummings,

Essere SIGAR sotto la GPL non ti impedisce di usarlo, significa solo che devi contattare gli autori e richiedere licenze alternative. Gli autori sono spesso felici di accettare una piccola tassa e consentire licenze commerciali.
Alec Thomas,

7
Dalla versione 1.6.4 SIGAR utilizza la licenza Apache.
Soundlink

sai come ottenere il carico per ogni singolo processore?
zcaudate,

Risposte:


67

Sulla falsariga di ciò che ho citato in questo post . Ti consiglio di usare l' API SIGAR . Uso l'API SIGAR in una delle mie applicazioni ed è fantastico. Lo troverai stabile, ben supportato e pieno di esempi utili. È open-source con una licenza GPL 2 Apache 2.0. Controlla. Ho la sensazione che soddisferà le tue esigenze.

Usando Java e l'API Sigar puoi ottenere informazioni su memoria, CPU, disco, media del carico, informazioni e metriche dell'interfaccia di rete, informazioni sulla tabella dei processi, informazioni sul percorso, ecc.


14
Fai attenzione quando usi Sigar, ci sono problemi su macchine x64 ... stackoverflow.com/questions/23405832/… e sembra che la libreria non venga aggiornata dal 2010
Alvaro

56

Quanto segue presumibilmente ti dà CPU e RAM. Vedi ManagementFactory per maggiori dettagli.

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
}

3
Esempio di output per il codice sopra. Questo codice funziona su Java 1.5. getCommittedVirtualMemorySize = 28622848 getFreePhysicalMemorySize = 228462592 getFreeSwapSpaceSize = 1129848832 getProcessCpuTime = 390625000 getTotalPhysicalMemorySize = 2147483647 getTotalSwapSpaceSize = 4294967295
blak3r

AFAIK getProcessCpuTime = 390625000 è solo il tempo di esecuzione del thread. Questo non è davvero utile per determinare l'utilizzo del processore
MikeNereson,

2
Non sono sicuro che sia effettivamente affidabile. Su Windows XP con 4 GB di memoria fisica riporta solo 2 GB (testato con Java 6 e Java 7). Anche la dimensione totale dello scambio è errata.
Emmanuel Bourg,

4
@EmmanuelBourg solo per documentare per le persone che vedono questo argomento, c'è un bug relativo a questo.
Sérgio Michels,

2
Questo metodo ha funzionato benissimo fino a Java 9, ora genera un java.lang.reflect.InaccessibleObjectException a causa del nuovo framework di controllo degli accessi che Java sta utilizzando.
Thor Lancaster,

40

In JDK 1.7, è possibile ottenere l'utilizzo della CPU e della memoria di sistema tramite com.sun.management.OperatingSystemMXBean. Questo è diverso da 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.

5
Sembra che questo sia incostante. Ottenere -1 per il carico della CPU su FreeBSD 10 e OpenJDK 8.
cen

controlla questa domanda stackoverflow.com/q/19781087/1206998 . dice che ci vogliono un paio di secondi per essere efficace. (nota: non ho provato)
Juh_

25

Questo funziona perfettamente per me senza alcuna API esterna, solo funzionalità nascosta Java nativa :)

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

Sinceramente trovo che questa sia la risposta migliore, funziona su Linux, quindi sono felice.
ArsenArsen

1
qualche idea del perché una seconda invocazione mostra 0,0? Su OpenJDK v8.
Vorburger,

Non dimenticare: "import java.lang.management.ManagementFactory;"
Bernd,

1
getProcessCpuLoad e getSystemCpuLoad restituiscono -1 da me.
sto

Non ha un metodo per ottenere il conteggio delle discussioni? Mi chiedo solo perché?
Djangofan,

16

Dai un'occhiata a questo articolo molto dettagliato: http://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarking#UsingaSuninternalclasstogetJVMCPUtime

Per ottenere la percentuale di CPU utilizzata, tutto ciò che serve sono alcuni semplici calcoli:

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

Nota: è necessario importare com.sun.management.OperatingSystemMXBeane non java.lang.management.OperatingSystemMXBean.


Questa è davvero una buona risposta Tutte le altre tecniche danno risultati davvero strani e inaffidabili, ma questa con una media finale ha funzionato come un incantesimo per me.
Frattaly,

Quando il tempo della CPU è superiore al tempo trascorso (ottengo più del 100%), è solo a causa del multithreading o come capirlo?
Lukas Hanacek,

8

Per lo spazio su disco, se si dispone di Java 6, è possibile utilizzare i metodi getTotalSpace e getFreeSpace su File. Se non sei su Java 6, credo che tu possa usare Apache Commons IO per arrivarci.

Non conosco alcun modo multipiattaforma per ottenere l'utilizzo della CPU o della memoria, temo.


6

Molti di questi sono già disponibili tramite JMX. Con Java 5, JMX è integrato e includono un visualizzatore console JMX con JDK.

È possibile utilizzare JMX per monitorare manualmente o richiamare i comandi JMX da Java se sono necessarie queste informazioni nel proprio runtime.



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

4

Il seguente codice è solo Linux (forse Unix), ma funziona in un vero progetto.

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

1
Questo è in realtà quello che stavo cercando, ma al codice manca lo schema REGEX per trovare le informazioni della cpu dal / proc / stat
Donal Tobin

qual è lo schema ??
HCarrasko,

3

Crea un file batch "Pc.bat" come, typeperf -sc 1 "\ mukit \ processor (_Total) \ %% Tempo processore"

Puoi usare la classe MProcess,

/ *
 * Md. Mukit Hasan
 * CSE-JU, 35
 ** / import java . io . *;

pubblico class MProcessor {

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

}

Quindi, dopo un po 'di manipolazione delle stringhe, si ottiene l'uso della CPU. È possibile utilizzare lo stesso processo per altre attività.

- Mukit Hasan


1
per me (Win XP) la riga di comando corretta era: typeperf "\processor(_total)\% processor time"Se lo metti nel file batch, usa %% invece di%. Ho usato technet.microsoft.com/en-us/library/bb490960.aspx .
tutejszy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.