Como monitoro a CPU, a memória e o uso do disco do computador em Java?

180

Gostaria de monitorar as seguintes informações do sistema em Java:

  • Uso atual da CPU ** (porcentagem)
  • Memória disponível * (livre / total)
  • Espaço em disco disponível (livre / total)

    * Observe que quero dizer memória geral disponível para todo o sistema, não apenas a JVM.

Estou procurando uma solução de plataforma cruzada (Linux, Mac e Windows) que não dependa do meu próprio código chamando programas externos ou usando JNI. Embora essas sejam opções viáveis, eu preferiria não manter o código específico do SO, se alguém já tiver uma solução melhor.

Se houver uma biblioteca gratuita por aí que faça isso de maneira confiável e multiplataforma, isso seria ótimo (mesmo que faça chamadas externas ou use o próprio código nativo).

Todas as sugestões são muito apreciadas.

Para esclarecer, gostaria de obter o uso atual da CPU para todo o sistema, não apenas os processos Java.

A API do SIGAR fornece todas as funcionalidades que estou procurando em um pacote, por isso é a melhor resposta para minha pergunta até agora. No entanto, por ser licenciado sob a GPL, não posso usá-lo para meu propósito original (um produto comercial de fonte fechada). É possível que a Hyperic possa licenciar o SIGAR para uso comercial, mas ainda não o examinei. Para meus projetos GPL, definitivamente considerarei o SIGAR no futuro.

Para minhas necessidades atuais, estou inclinado para o seguinte:

  • Para uso da CPU, OperatingSystemMXBean.getSystemLoadAverage() / OperatingSystemMXBean.getAvailableProcessors()(média de carga por CPU)
  • Para memória OperatingSystemMXBean.getTotalPhysicalMemorySize()eOperatingSystemMXBean.getFreePhysicalMemorySize()
  • Para espaço em disco File.getTotalSpace()eFile.getUsableSpace()

Limitações:

Os getSystemLoadAverage()métodos de consulta de espaço em disco e estão disponíveis apenas no Java 6. Além disso, algumas funcionalidades do JMX podem não estar disponíveis para todas as plataformas (ou seja, foi relatado que getSystemLoadAverage()retorna -1 no Windows).

Embora originalmente licenciado sob a GPL, foi alterado para Apache 2.0 , que geralmente pode ser usado para produtos comerciais de código fechado.

David Crow
fonte
Para esclarecer, a sigar api fornece informações do sistema. Se você quiser informações sobre jvm, use JMX.
7118 Matt Cummings
O SIGAR sob a GPL não o impede de usá-lo, apenas significa que você deve entrar em contato com os autores e solicitar um licenciamento alternativo. Os autores geralmente ficam felizes em aceitar uma pequena taxa e permitir o licenciamento comercial.
Alec Thomas
7
Desde a versão 1.6.4, o SIGAR está usando a licença Apache.
Soundlink
você sabe como obter a carga para cada processador individual?
Zcaudate 12/09/12

Respostas:

67

Na linha do que mencionei neste post . Eu recomendo que você use a API SIGAR . Eu uso a API SIGAR em um dos meus próprios aplicativos e é ótimo. Você descobrirá que é estável, bem suportado e cheio de exemplos úteis. É de código aberto com uma licença GPL 2 Apache 2.0. Confira. Tenho a sensação de que atenderá às suas necessidades.

Usando Java e a API Sigar, você pode obter informações, métricas, memória, CPU, disco, média de carga, interface de rede, informações da tabela de processos, informações de rotas, etc.

Matt Cummings
fonte
14
Tenha cuidado ao usar Sigar, há problemas em máquinas x64 ... stackoverflow.com/questions/23405832/... e parece que a biblioteca não é atualizado desde 2010
Alvaro
56

O seguinte supostamente fornece CPU e RAM. Veja ManagementFactory para mais detalhes.

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
fonte
3
Exemplo de saída para o código acima. Este código funciona no Java 1.5. getCommittedVirtualMemorySize = 28622848 getFreePhysicalMemorySize = 228462592 getFreeSwapSpaceSize = 1129848832 getProcessCpuTime = 390625000 getTotalPhysicalMemorySize = 2147483647 getTotalSwapSpaceSize = 4294967295
blak
AFAIK getProcessCpuTime = 390625000 é apenas por quanto tempo esse encadeamento está em execução. Isso não é realmente útil para determinar o uso do processador
MikeNereson
2
Não tenho certeza se é realmente confiável. No Windows XP com 4 GB de memória física, ele relata apenas 2 GB (testado com Java 6 e Java 7). O tamanho total da troca também está errado.
Emmanuel Bourg
4
@EmmanuelBourg apenas para documentar as pessoas que veem esse tópico, há um bug relacionado a isso.
Sérgio Michels
2
Esse método funcionou muito bem até o Java 9, agora lança uma java.lang.reflect.InaccessibleObjectException devido à nova estrutura de verificação de acesso que Java está usando.
26419 Thor Lancaster
40

No JDK 1.7, é possível obter o uso da CPU e da memória do sistema via com.sun.management.OperatingSystemMXBean. Isso é diferente de 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
fonte
5
Parece que isso é um sucesso. Obtendo -1 para a carga da CPU no FreeBSD 10 e OpenJDK 8.
cen
verifique esta pergunta stackoverflow.com/q/19781087/1206998 . diz que leva alguns segundos para ser eficaz. (nota: eu não tentei)
Juh_
25

Isso funciona perfeitamente para mim sem nenhuma API externa, apenas o recurso oculto do Java nativo :)

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
fonte
Sinceramente, acho essa a melhor resposta, funciona no Linux, então estou feliz.
ArsenArsen # 4/16
1
alguma pista por que uma segunda invocação mostra 0,0? No OpenJDK v8.
vorburger
Não se esqueça: "import java.lang.management.ManagementFactory;"
Bernd
1
getProcessCpuLoad e getSystemCpuLoad retornam -1 de mim. Estou usando o jdk 1.8
Burak Akyıldız
Não possui um método para obter a contagem de threads? Apenas me perguntando por quê?
djangofan
16

Consulte este artigo muito detalhado: http://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarking#UsingaSuninternalclasstogetJVMCPUtime

Para obter a porcentagem de CPU usada, tudo que você precisa é de algumas contas 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: Você deve importar com.sun.management.OperatingSystemMXBeane não java.lang.management.OperatingSystemMXBean.

ludovicc
fonte
Esta é uma resposta muito boa. Todas as outras técnicas dão resultados realmente estranhos e pouco confiáveis, mas esta com algumas médias finais funcionou como um encanto para mim.
Fractaly 12/08/19
Quando o tempo da CPU é maior que o tempo decorrido (eu recebo mais de 100%), é apenas por causa do multithreading, ou como entendê-lo?
Lukas Hanacek 03/03
8

Para espaço em disco, se você tem o Java 6, você pode usar os getTotalSpace e GetFreeSpace métodos em Arquivo. Se você não está no Java 6, acredito que você pode usar o Apache Commons IO para chegar até lá.

Não sei de nenhuma maneira de plataforma cruzada para obter o uso da CPU ou o uso da memória.

Matt Sheppard
fonte
6

Muito disso já está disponível via JMX. Com o Java 5, o JMX é incorporado e eles incluem um visualizador de console JMX com o JDK.

Você pode usar o JMX para monitorar manualmente ou chamar comandos JMX a partir de Java se precisar dessas informações em seu próprio tempo de execução.

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

O código a seguir é apenas Linux (talvez Unix), mas funciona em um projeto 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
fonte
1
Este é realmente o que eu estava procurando, mas o código está faltando o padrão REGEX para encontrar as informações cpu do / proc / stat
Donal Tobin
qual é o padrão ??
precisa saber é o seguinte
3

Crie um arquivo em lotes "Pc.bat" como, digiteperf -sc 1 "\ mukit \ processor (_Total) \ %% Tempo do processador"

Você pode usar a classe MProcess,

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

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

}

Depois de alguma manipulação de string, você obtém o uso da CPU. Você pode usar o mesmo processo para outras tarefas.

--Mukit Hasan

Md. Mukit Hasan
fonte
1
para mim (Win XP), a linha de comando apropriada era: typeperf "\processor(_total)\% processor time"Se você o colocar em arquivo em lotes, use %% em vez de%. Eu usei technet.microsoft.com/en-us/library/bb490960.aspx .
precisa saber é o seguinte