¿Cómo monitorizo ​​el uso de CPU, memoria y disco de la computadora en Java?

180

Me gustaría monitorear la siguiente información del sistema en Java:

  • Uso actual de la CPU ** (porcentaje)
  • Memoria disponible * (libre / total)
  • Espacio disponible en disco (libre / total)

    * Tenga en cuenta que me refiero a la memoria general disponible para todo el sistema, no solo la JVM.

Estoy buscando una solución multiplataforma (Linux, Mac y Windows) que no se base en mi propio código para llamar a programas externos o usar JNI. Aunque estas son opciones viables, preferiría no mantener yo mismo el código específico del sistema operativo si alguien ya tiene una mejor solución.

Si hay una biblioteca gratuita por ahí que lo haga de manera confiable y multiplataforma, sería genial (incluso si realiza llamadas externas o utiliza el código nativo).

Cualquier sugerencia es muy apreciada.

Para aclarar, me gustaría obtener el uso actual de la CPU para todo el sistema, no solo los procesos de Java.

La API SIGAR proporciona toda la funcionalidad que busco en un paquete, por lo que es la mejor respuesta a mi pregunta hasta ahora. Sin embargo, debido a que tiene licencia bajo la GPL, no puedo usarlo para mi propósito original (una fuente cerrada, producto comercial). Es posible que Hyperic pueda licenciar SIGAR para uso comercial, pero no lo he investigado. Para mis proyectos GPL, definitivamente consideraré SIGAR en el futuro.

Para mis necesidades actuales, me inclino por lo siguiente:

  • Para uso de CPU, OperatingSystemMXBean.getSystemLoadAverage() / OperatingSystemMXBean.getAvailableProcessors() (promedio de carga por CPU)
  • Por memoria, OperatingSystemMXBean.getTotalPhysicalMemorySize()yOperatingSystemMXBean.getFreePhysicalMemorySize()
  • Para espacio en disco, File.getTotalSpace()yFile.getUsableSpace()

Limitaciones:

Los getSystemLoadAverage()métodos de consulta y espacio en disco solo están disponibles en Java 6. Además, algunas funciones de JMX pueden no estar disponibles para todas las plataformas (es decir, se ha informado quegetSystemLoadAverage() devuelve -1 en Windows).

Aunque originalmente tenía licencia bajo GPL, se ha cambiado a Apache 2.0 , que generalmente se puede usar para productos comerciales de código cerrado.

David Crow
fuente
Para aclarar, la API de sigar te proporciona información del sistema. Si quieres información jvm usa JMX.
Matt Cummings
El hecho de que SIGAR esté bajo la GPL no le impide usarlo, solo significa que debe comunicarse con los autores y solicitar una licencia alternativa. Los autores a menudo se complacen en aceptar una pequeña tarifa y permitir licencias comerciales.
Alec Thomas el
77
Desde la versión 1.6.4, SIGAR utiliza la licencia de Apache.
Soundlink
¿Sabes cómo obtener la carga para cada procesador individual?
zcaudate

Respuestas:

67

En la línea de lo que mencioné en esta publicación . Te recomiendo que uses la API SIGAR . Uso la API SIGAR en una de mis propias aplicaciones y es genial. Encontrará que es estable, bien soportado y lleno de ejemplos útiles. Es de código abierto con una licencia GPL 2 Apache 2.0. Echale un vistazo. Tengo la sensación de que satisfará tus necesidades.

Con Java y la API de Sigar, puede obtener memoria, CPU, disco, promedio de carga, información y métricas de la interfaz de red, información de la tabla de procesos, información de ruta, etc.

Matt Cummings
fuente
14
Tenga cuidado al usar Sigar, hay problemas en las máquinas x64 ... stackoverflow.com/questions/23405832/… y parece que la biblioteca no se actualiza desde 2010
Alvaro
56

Lo siguiente supuestamente te da CPU y RAM. Ver ManagementFactory para más detalles.

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
fuente
3
Salida de muestra para el código anterior. Este código funciona en Java 1.5. getCommittedVirtualMemorySize = 28622848 getFreePhysicalMemorySize = 228462592 getFreeSwapSpaceSize = 1129848832 getProcessCpuTime = 390625000 getTotalPhysicalMemorySize = 2147483647 getTotalSwapSpaceSize = 4294967295
blak3r
AFAIK getProcessCpuTime = 390625000 es solo cuánto tiempo ha estado funcionando ese subproceso. Eso no es realmente útil para determinar el uso del procesador
MikeNereson
2
No estoy seguro de que sea realmente confiable. En Windows XP con 4GB de memoria física solo reporta 2GB (probado con Java 6 y Java 7). El tamaño de intercambio total también es incorrecto.
Emmanuel Bourg
44
@EmmanuelBourg solo para documentar a las personas que ven este tema, hay un error relacionado con esto.
Sérgio Michels
2
Este método funcionó muy bien hasta Java 9, ahora arroja una excepción java.lang.reflect.InaccessibleObjectException debido al nuevo marco de comprobación de acceso que Java está utilizando.
Thor Lancaster
40

En JDK 1.7, puede obtener el uso de CPU y memoria del sistema a través de com.sun.management.OperatingSystemMXBean. Esto es diferente a 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
fuente
55
Parece que esto es impredecible. Obteniendo -1 para carga de CPU en FreeBSD 10 y OpenJDK 8.
cen
consulte esta pregunta stackoverflow.com/q/19781087/1206998 . dice que se tarda unos segundos en ser efectivo. (nota: no lo intenté)
Juh_
25

Esto funciona para mí perfectamente sin ninguna API externa, solo la función oculta de 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());
bizzr3
fuente
Sinceramente, esta es la mejor respuesta, funciona en Linux, así que estoy feliz.
ArsenArsen
1
alguna pista de por qué una segunda invocación muestra 0.0? En OpenJDK v8.
vorburger
No olvide: "import java.lang.management.ManagementFactory;"
Bernd
1
getProcessCpuLoad y getSystemCpuLoad return -1 me forman. estoy usando jdk 1.8
Burak Akyıldız
¿No tiene un método para obtener el recuento de hilos? ¿Solo me pregunto por qué?
djangofan
16

Echa un vistazo a este artículo muy detallado: http://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarking#UsingaSuninternalclasstogetJVMCPUtime

Para obtener el porcentaje de CPU utilizado, todo lo que necesita son algunas matemáticas simples:

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: debe importar com.sun.management.OperatingSystemMXBeany no java.lang.management.OperatingSystemMXBean.

ludovicc
fuente
Esta es una muy buena respuesta. Todas las otras técnicas dan resultados realmente extraños y poco confiables, pero esta con un promedio de seguimiento funcionó de maravilla para mí.
Fractaly
Cuando el tiempo de la CPU es más alto que el tiempo transcurrido (obtengo más del 100%), ¿es solo por el subprocesamiento múltiple o por cómo entenderlo?
Lukas Hanacek
8

Para espacio en disco, si tiene Java 6, puede usar los métodos getTotalSpace y getFreeSpace en File. Si no está en Java 6, creo que puede usar Apache Commons IO para llegar hasta allí.

No conozco ninguna forma multiplataforma para obtener el uso de CPU o el uso de memoria, me temo.

Matt Sheppard
fuente
6

Mucho de esto ya está disponible a través de JMX. Con Java 5, JMX está integrado e incluye un visor de consola JMX con el JDK.

Puede usar JMX para monitorear manualmente o invocar comandos JMX desde Java si necesita esta información en su propio tiempo de ejecución.

Jason Cohen
fuente
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
fuente
4

El siguiente código es Linux (quizás Unix) solamente, pero funciona en un proyecto real.

    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
fuente
1
Esto es realmente lo que estaba buscando, pero al código le falta el patrón REGEX para encontrar la información de la CPU de / proc / stat
Donal Tobin
¿Cuál es el patrón?
HCarrasko
3

Cree un archivo por lotes "Pc.bat" como, typeperf -sc 1 "\ mukit \ processor (_Total) \ %% Processor Time"

Puedes usar la clase MProcess,

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

público de clase 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()); } }

}

Luego, después de manipular algunas cadenas, obtienes el uso de la CPU. Puede usar el mismo proceso para otras tareas.

--Mukit Hasan

Md. Mukit Hasan
fuente
1
para mí (Win XP) la línea de comando adecuada era: typeperf "\processor(_total)\% processor time"si lo coloca en un archivo por lotes, use %% en lugar de%. Solía technet.microsoft.com/en-us/library/bb490960.aspx .
tutejszy