Obter informações do sistema no nível do sistema operacional

232

Atualmente, estou criando um aplicativo Java que pode acabar sendo executado em muitas plataformas diferentes, mas principalmente em variantes do Solaris, Linux e Windows.

Alguém conseguiu extrair com sucesso informações como o espaço em disco atual usado, a utilização da CPU e a memória usada no sistema operacional subjacente? E o que o próprio aplicativo Java está consumindo?

De preferência, eu gostaria de obter essas informações sem usar o JNI.

Steve M
fonte
3
Com relação à memória livre ver stackoverflow.com/a/18366283/231397 ( Runtime.getRuntime().freeMemory()como sugerido na resposta aceita NÃO dado a quantidade de memória livre.
Fries cristãs

Respostas:

206

Você pode obter algumas informações de memória limitadas da classe Runtime. Realmente não é exatamente o que você está procurando, mas pensei em fornecer isso por uma questão de integridade. Aqui está um pequeno exemplo. Editar: Você também pode obter informações de uso do disco da classe java.io.File. O material de uso do espaço em disco requer Java 1.6 ou superior.

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
fonte
7
Eu acho que "a memória total atualmente em uso pela JVM" é um pouco confusa. O javadoc diz que a função retorna "a quantidade total de memória atualmente disponível para objetos atuais e futuros, medidos em bytes". Parece mais com a memória restante e não sendo usada.
Dirk
@Dirk: Eu atualizei o texto para endereçar seu comentário. Obrigado!
William Brendel
@ LeonardoGaldioli: Não conheço as características de desempenho dessas classes e métodos, mas não ficaria surpreso se não fossem otimizados para velocidade. Outras respostas explicam como coletar determinadas informações usando o JMX, que podem ser mais rápidas.
William Brendel
15
Isso não responde à pergunta corretamente. Todos os que reefers dados para JVM e não para o OS ...
Alvaro
Eu sei que este tópico está bastante desatualizado. MAS: Se você realmente precisa da quantidade de núcleos da CPU, não use esta solução. Eu tenho uma CPU dual-core com dois threads para cada núcleo. A JVM não retorna os núcleos de hardware, mas os núcleos / threads de software.
F_Schmidt 19/06
95

O pacote java.lang.management fornece muito mais informações que o Runtime - por exemplo, ele fornece memória heap ( ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()) separada da memória não heap ( ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage()).

Você também pode obter o uso da CPU do processo (sem escrever seu próprio código JNI), mas você precisa para lançar o java.lang.management.OperatingSystemMXBeana um com.sun.management.OperatingSystemMXBean. Isso funciona no Windows e Linux, eu não testei em nenhum outro lugar.

Por exemplo ... chame o método get getCpuUsage () com mais frequência para obter leituras mais precisas.

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();
        }
    }
}
Patrick Wilkes
fonte
10
Para obtê-lo para compilar, substitua o elenco OperatingSystemMXBeanpara com.sun.management.OperatingSystemMXBeane prefácio todas as instâncias getOperatingSystemMXBean()com ManagementFactory.. Você precisa importar todas as classes adequadamente.
tmarthal
2
Estou recebendo o uso da CPU como 0 para tudo. Alterei a fórmula de uso da CPU para cpuUsage = processCpuTime / systemTime. Estou recebendo um valor para uso da CPU que eu não entendo.
27412 Raj
faz 1,0 como resultado do getCpuUsagesignificativo que o sistema é usando todas as suas availableProcessors a 100%?
User454322
2
Eu sempre recebo 0 como @Raj disse ... você poderia dar um exemplo de como usar esse código?
dm76
1
Tente((double)( processCpuTime - lastProcessCpuTime )) / ((double)( systemTime - lastSystemTime ))
Anthony O.
43

Eu acho que o melhor método disponível para implementar a API SIGAR da Hyperic . Ele funciona para a maioria dos principais sistemas operacionais (muito perto de qualquer coisa moderna) e é muito fácil de trabalhar. Os desenvolvedores são muito responsivos em seus fóruns e listas de discussão. Também gosto que seja licenciado pela GPL2 Apache . Eles fornecem uma tonelada de exemplos em Java também!

SIGAR == Sistema de informações, coleta e relatórios ferramenta.

Matt Cummings
fonte
2
@Yohan - Não seja preguiçoso! Você pode descobrir isso lendo a página vinculada. (E isso depende do que você entende por "independente de plataforma".)
Stephen C
2
@StephenC: O Sigar está usando arquivos .dll, o que o torna dependente da plataforma. O nível API maior pode estar em Java, é uma história diferente
Suco de limão
1
@Artificial_Intelligence sim, mas fornece bibliotecas (escritas em c) para as plataformas mais populares. Não é mais dependente da plataforma do que a própria jvm. A API Java de nível superior deve ser consistente em todas as plataformas.
precisa saber é o seguinte
8
Sigar não é atualizado desde 2010 e parece ter um bug em 64 sistemas de bits: stackoverflow.com/questions/23405832/...
Alvaro
1
E o SIGAR também causa a falha da JVM (embora intermitente), mas tenho certeza de que você não correrá esse risco na produção.
AKS 14/06
25

Há um projeto Java que usa JNA (portanto, não há bibliotecas nativas para instalar) e está em desenvolvimento ativo. Atualmente, ele suporta Linux, OSX, Windows, Solaris e FreeBSD e fornece informações sobre RAM, CPU, bateria e sistema de arquivos.

dB.
fonte
Talvez nenhuma biblioteca nativa seja enganosa. O projeto usa bibliotecas nativas, mesmo que não tenham escrito, e você aparentemente não precisa instalar nenhuma.
Stephen C
1
Você está certo. O JNA usa libffi que possui componentes nativos. Mas, para todos os efeitos, parece que não há bibliotecas nativas (definitivamente não há nenhuma para instalar).
dB.
@StephenC, embora o que você diz seja preciso, é enganoso, porque é o mesmo para o rt.jar, que também chama métodos nativos. a única razão pela qual as pessoas se preocupam com métodos nativos é que eles precisam compilar e / ou instalá-los, o que geralmente é uma tarefa não trivial. como a libffi é amplamente adotada, portada e instalada, mitiga as dificuldades. então, tecnicamente, você está correto, mas praticamente não importa.
Rbp
@rbp - Há outra razão pela qual as pessoas desenvolvedores Java experientes preferem evitar bibliotecas nativas. Uma biblioteca nativa que possui bugs (incluindo problemas de segurança de encadeamento ou problemas com gerenciamento de memória) pode desestabilizar a JVM do host. Este não é um "não importa" problema ....
Stephen C
@StephenC ter criado o servidor de aplicativos weblogic me fez ter experiência suficiente?
Rbp
13

Para janelas eu fui por aqui.

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

Aqui está o link com detalhes.

Yan Khonski
fonte
11

Você pode obter algumas informações no nível do sistema usando System.getenv(), passando o nome da variável de ambiente relevante como parâmetro. Por exemplo, no Windows:

System.getenv("PROCESSOR_IDENTIFIER")
System.getenv("PROCESSOR_ARCHITECTURE")
System.getenv("PROCESSOR_ARCHITEW6432")
System.getenv("NUMBER_OF_PROCESSORS")

Para outros sistemas operacionais, a presença / ausência e os nomes das variáveis ​​de ambiente relevantes serão diferentes.

Alexandr
fonte
1
Eles dependem da plataforma porque os nomes das variáveis ​​são diferentes entre os sistemas. O artigo da Oracle sobre variáveis ​​de ambiente informa isso. Também estou encontrando uma maneira de obter uma maneira independente do sistema.
Lemon Juice
No Linux (Ubuntu 17.10), não há muitas informações interessantes sobre processadores no ambiente.
Pventjer
8

Adicione dependência OSHI via maven:

<dependency>
    <groupId>com.github.dblock</groupId>
    <artifactId>oshi-core</artifactId>
    <version>2.2</version>
</dependency>

Obtenha uma capacidade da bateria restante em porcentagem:

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
fonte
OSHI tem a maioria das informações descritas nos outros comentários. Ele usa o JNA para obtê-lo através de chamadas nativas do SO, quando possível.
Daniel Widdis
6

Veja as APIs disponíveis no pacote java.lang.management . Por exemplo:

  • OperatingSystemMXBean.getSystemLoadAverage()
  • ThreadMXBean.getCurrentThreadCpuTime()
  • ThreadMXBean.getCurrentThreadUserTime()

Existem muitas outras coisas úteis lá também.

staffan
fonte
2
OperatingSystemMXBean.getSystemLoadAverage () não está implementada no Windows porque "seu demasiado caro"
MikeNereson
1
ThreadMXBean.getCurrentThreadCpuTime () retorna apenas por quanto tempo esse thread está em execução. Não é a porcentagem de uso da CPU.
21410 MikeNereson
5

Geralmente, para obter informações de baixo nível do sistema operacional, você pode chamar comandos específicos do sistema operacional que fornecem as informações desejadas com o Runtime.exec () ou ler arquivos como / proc / * no Linux.

Peter Lawrey
fonte
5

O uso da CPU não é simples - java.lang.management via com.sun.management.OperatingSystemMXBean.getProcessCpuTime chega perto (consulte o excelente trecho de código de Patrick acima), mas observe que ele só dá acesso ao tempo que a CPU gastou em seu processo. ele não informa sobre o tempo de CPU gasto em outros processos ou mesmo o tempo de CPU executando atividades do sistema relacionadas ao seu processo.

por exemplo, eu tenho um processo java intensivo em rede - é a única coisa em execução e a CPU está em 99%, mas apenas 55% disso é relatado como "CPU do processador".

nem me inicie na "carga média", pois é quase inútil, apesar de ser o único item relacionado à CPU no bean MX. se apenas o sol em sua sabedoria ocasional expusesse algo como "getTotalCpuTime" ...

para monitoramento sério da CPU, o SIGAR mencionado por Matt parece ser a melhor aposta.

Parcialmente nublado
fonte
4

Em Windows, você pode executar o systeminfocomando e recuperar sua saída, por exemplo, com o seguinte código:

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
fonte
3

Se você estiver usando o Jrockit VM, eis uma outra maneira de obter o uso da CPU da VM. O bean de tempo de execução também pode fornecer a carga da CPU por processador. Eu usei isso apenas no Red Hat Linux para observar o desempenho do Tomcat. Você precisa habilitar o JMX remote em catalina.sh para que isso funcione.

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
fonte
3

Ainda está em desenvolvimento, mas você já pode usar o jHardware

É uma biblioteca simples que captura dados do sistema usando Java. Funciona em Linux e 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
fonte
Bom, mas ele usa as versões Guava e JNA que estão em conflito com minhas necessidades (por exemplo, consulte GLASSFISH-21367 ).
23617 lu_ko
Olá, o JNA foi introduzido na versão 0.8 do jHardware. É usado apenas para dados de temperatura e sensores. Se você não precisar dessas informações, poderá usar a versão 0.7. A mesma coisa para a goiaba. Nesse caso, você terá que usar a versão 0.6.3.
31517
2

Uma maneira simples que pode ser usada para obter as informações no nível do SO e eu testei no meu Mac, que funciona bem:

 OperatingSystemMXBean osBean =
        (OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
    return osBean.getProcessCpuLoad();

Você pode encontrar muitas métricas relevantes do sistema operacional aqui

Amandeep Singh
fonte
1

Ei, você pode fazer isso com a integração java / com. Ao acessar os recursos WMI, você pode obter todas as informações.


fonte
0

Para obter a média de carregamento do sistema de 1 minuto, 5 minutos e 15 minutos dentro do código java, você pode fazer isso executando o comando cat /proc/loadavgusando e interpretando-o como abaixo:

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

E para obter a memória do sistema físico executando o comando free -me interpretando-o como abaixo:

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
fonte