Ottieni informazioni sul sistema a livello di sistema operativo


232

Attualmente sto costruendo un'app Java che potrebbe essere eseguita su molte piattaforme diverse, ma principalmente varianti di Solaris, Linux e Windows.

Qualcuno è stato in grado di estrarre con successo informazioni come lo spazio su disco corrente utilizzato, l'utilizzo della CPU e la memoria utilizzata nel sistema operativo sottostante? Che dire di ciò che l'app Java stessa sta consumando?

Preferibilmente vorrei ottenere queste informazioni senza usare JNI.


3
Per quanto riguarda la memoria libera, consultare stackoverflow.com/a/18366283/231397 ( Runtime.getRuntime().freeMemory()come suggerito nella risposta accettata NON vi dà la quantità di memoria libera.
Christian Fries

Risposte:


206

È possibile ottenere alcune informazioni sulla memoria limitate dalla classe Runtime. Non è esattamente quello che stai cercando, ma ho pensato che l'avrei fornito per completezza. Ecco un piccolo esempio. Modifica: è inoltre possibile ottenere informazioni sull'utilizzo del disco dalla classe java.io.File. L'utilizzo dello spazio su disco richiede Java 1.6 o versione successiva.

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

7
Penso che "La memoria totale attualmente utilizzata dalla JVM" sia un po 'confusa. Il javadoc afferma che la funzione restituisce "la quantità totale di memoria attualmente disponibile per gli oggetti attuali e futuri, misurata in byte". Sembra più memoria rimanente e non in uso.
Dirk,

@Dirk: ho aggiornato il testo per rispondere al tuo commento. Grazie!
William Brendel,

@LeonardoGaldioli: non conosco le caratteristiche prestazionali di queste classi e metodi, ma non sarei sorpreso se non fossero ottimizzati per la velocità. Altre risposte spiegano come raccogliere determinate informazioni usando JMX, che potrebbe essere più veloce.
William Brendel,

15
Questo non risponde correttamente alla domanda. Tutto quel dato fa barriera a JVM e non al sistema operativo ...
Alvaro,

So che questo argomento è abbastanza obsoleto. MA: se hai davvero bisogno della quantità di core della CPU, allora non usare questa soluzione. Ho una CPU dual-core con due thread per ogni core. JVM non restituisce i core hardware, ma piuttosto i core / thread del software.
F_Schmidt,

95

Il pacchetto java.lang.management fornisce molte più informazioni di Runtime, ad esempio ti darà memoria heap ( ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()) separata dalla memoria non heap ( ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage()).

È inoltre possibile ottenere l'utilizzo della CPU del processo (senza scrivere il proprio codice JNI), ma è necessario eseguire il cast java.lang.management.OperatingSystemMXBeandi a com.sun.management.OperatingSystemMXBean. Funziona su Windows e Linux, non l'ho provato altrove.

Ad esempio ... chiama il metodo get getCpuUsage () più frequentemente per ottenere letture più accurate.

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

10
Per farlo compilare, sostituire il cast OperatingSystemMXBeandi com.sun.management.OperatingSystemMXBeane prefazione tutte le istanze di getOperatingSystemMXBean()con ManagementFactory.. Devi importare tutte le classi in modo appropriato.
Martedì

2
Ricevo l'utilizzo della CPU come 0 per tutto. ho cambiato la formula di utilizzo della cpu in cpuUsage = processCpuTime / systemTime. Sto ottenendo un valore per l'utilizzo della CPU che non capisco.
Raj

fa 1,0 come risultato getCpuUsagemedio che il sistema sta usando tutte le sue availableProcessors al 100%?
user454322

2
Ottengo sempre 0 come ha detto @Raj ... potresti dare un esempio di come usare quel codice?
dm76,

1
Prova((double)( processCpuTime - lastProcessCpuTime )) / ((double)( systemTime - lastSystemTime ))
Anthony O.

43

Penso che il metodo migliore in circolazione sia implementare l' API SIGAR di Hyperic . Funziona con la maggior parte dei principali sistemi operativi (dannatamente vicino a qualsiasi cosa moderna) ed è molto facile da lavorare. Gli sviluppatori sono molto reattivi sul loro forum e mailing list. Mi piace anche che abbia la licenza GPL2 Apache . Forniscono moltissimi esempi anche in Java!

SIGAR == Strumento di informazioni di sistema, raccolta e reportistica.


2
@Yohan - Non essere pigro! Puoi scoprirlo leggendo la pagina web collegata. (E dipende da cosa intendi per "piattaforma indipendente".)
Stephen C,

2
@StephenC: Sigar sta usando i file .dll, il che lo rende dipendente dalla piattaforma. L'API di livello superiore potrebbe essere in Java, è una storia diversa
Lemon Juice,

1
@Artificial_Intelligence sì, ma fornisce librerie (scritte in c) per le piattaforme più popolari. Non dipende più dalla piattaforma della stessa jvm. L'API Java di livello superiore deve essere coerente su tutte le piattaforme.
Jeshurun,

8
Sigar non viene aggiornato dal 2010 e sembra avere un bug su sistemi a 64 bit: stackoverflow.com/questions/23405832/…
Alvaro

1
E SIGAR provoca anche l'arresto anomalo di JVM, anche se intermittente, ma sono sicuro che non correrai questo rischio durante la produzione.
AKS,

25

C'è un progetto Java che utilizza JNA (quindi nessuna libreria nativa da installare) ed è in sviluppo attivo. Attualmente supporta Linux, OSX, Windows, Solaris e FreeBSD e fornisce informazioni su RAM, CPU, batteria e file system.


Nessuna biblioteca nativa è forse fuorviante. Il progetto utilizza librerie native, anche se non ne hanno scritte, e apparentemente non è necessario installarne nessuna.
Stephen C

1
Hai ragione. JNA usa libffi che ha componenti nativi. Ma a tutti gli effetti, sembra che non ci siano librerie native (sicuramente nessuna da installare).
dB.

@StephenC sebbene ciò che dici sia accurato, è fuorviante perché è lo stesso per rt.jar che invoca anche metodi nativi. l'unica ragione per cui le persone si preoccupano dei metodi nativi è che devono compilarli e / o installarli, che spesso è un'attività non banale. poiché libffi è adottato, portato e installato in modo così ampio, mitiga le difficoltà. quindi, tecnicamente hai ragione, ma praticamente, non importa.
rbp,

@rbp - C'è un altro motivo per cui gli sviluppatori Java esperti preferiscono evitare le librerie native. Una libreria nativa che presenta bug (inclusi problemi di sicurezza dei thread o problemi con la gestione della memoria) può destabilizzare la JVM host. Questo non è un problema "non importa" ....
Stephen C

@StephenC aver creato il server delle applicazioni weblogic mi ha fatto sperimentare abbastanza?
PB

13

Per Windows sono andato in questo modo.

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

Ecco il link con i dettagli.


11

È possibile ottenere alcune informazioni a livello di sistema utilizzando System.getenv(), passando il nome della variabile di ambiente pertinente come parametro. Ad esempio, su Windows:

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

Per altri sistemi operativi la presenza / assenza e i nomi delle variabili di ambiente rilevanti differiranno.


1
Questi dipendono dalla piattaforma perché i nomi delle variabili sono diversi tra i sistemi. L'articolo di Oracle sulle variabili d'ambiente lo dice. Sto anche trovando un modo per ottenere un modo indipendente dal sistema.
Succo di limone,

Sotto Linux (Ubuntu 17.10) non ci sono molte informazioni interessanti sui processori nell'ambiente.
pveentjer,

8

Aggiungi dipendenza OSHI tramite Maven:

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

Ottieni una capacità della batteria rimasta in percentuale:

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

OSHI ha la maggior parte delle informazioni descritte negli altri commenti. Usa JNA per ottenerlo tramite chiamate native del SO quando possibile.
Daniel Widdis,

6

Dai un'occhiata alle API disponibili nel pacchetto java.lang.management . Per esempio:

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

Ci sono anche molte altre cose utili.


2
OperatingSystemMXBean.getSystemLoadAverage () non è implementato in Windows perché "è troppo costoso"
MikeNereson,

1
ThreadMXBean.getCurrentThreadCpuTime () restituisce solo il tempo di esecuzione del thread. Non la percentuale di utilizzo della CPU.
MikeNereson,

5

Di solito, per ottenere informazioni sul sistema operativo di basso livello, è possibile chiamare comandi specifici del sistema operativo che forniscono le informazioni desiderate con Runtime.exec () o leggere file come / proc / * in Linux.


5

L'utilizzo della CPU non è semplice: java.lang.management tramite com.sun.management.OperatingSystemMXBean.getProcessCpuTime si avvicina (vedi l'eccellente frammento di codice di Patrick sopra) ma nota che dà accesso solo al tempo impiegato dalla CPU nel processo. non ti dirà del tempo della CPU speso in altri processi, né del tempo della CPU impiegato per svolgere attività di sistema relative al tuo processo.

ad esempio, ho un processo java ad alta intensità di rete: è l'unica cosa in esecuzione e la CPU è al 99%, ma solo il 55% è segnalato come "CPU del processore".

non farmi nemmeno iniziare con il "carico medio" dato che è quasi inutile, nonostante sia l'unico elemento relativo alla CPU sul bean MX. se solo il sole nella loro saggezza occasionale esponesse qualcosa come "getTotalCpuTime" ...

per un serio monitoraggio della CPU SIGAR citato da Matt sembra la scommessa migliore.


4

Windows, è possibile eseguire il systeminfocomando e recuperare l'output, ad esempio con il seguente codice:

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

3

Se si utilizza Jrockit VM, ecco un altro modo per ottenere l'utilizzo della CPU VM. Il bean di runtime può anche fornire il carico della CPU per processore. L'ho usato solo su Red Hat Linux per osservare le prestazioni di Tomcat. Devi abilitare il telecomando JMX in catalina.sh affinché funzioni.

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

3

È ancora in fase di sviluppo ma è già possibile utilizzarlo jHardware

È una semplice libreria che elimina i dati di sistema usando Java. Funziona sia in Linux che in 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());
//[...]

Bello, ma usa versioni di Guava e JNA che sono in conflitto con le mie esigenze (es. Vedi GLASSFISH-21367 ).
lu_ko,

Ciao, JNA è stato introdotto nella versione 0.8 di jHardware. Viene utilizzato solo per i dati di temperatura e sensori. Se non sono necessarie tali informazioni, è possibile utilizzare la versione 0.7. Stessa cosa per Guava. In tal caso dovrai utilizzare la versione 0.6.3.
profesor_falken,

2

Un modo semplice che può essere utilizzato per ottenere informazioni a livello di sistema operativo e ho testato sul mio Mac che funziona bene:

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

Puoi trovare molte metriche rilevanti del sistema operativo qui


1

Ehi, puoi farlo con l'integrazione java / com. Accedendo alle funzionalità WMI è possibile ottenere tutte le informazioni.


0

Per ottenere la media del caricamento del sistema di 1 minuto, 5 minuti e 15 minuti all'interno del codice java, è possibile farlo eseguendo il comando cat /proc/loadavgutilizzando e interpretandolo come di seguito:

    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 per ottenere la memoria di sistema fisica eseguendo il comando free -me quindi interpretandolo come di seguito:

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