Systeminformationen auf Betriebssystemebene abrufen

232

Ich baue derzeit eine Java-App, die möglicherweise auf vielen verschiedenen Plattformen ausgeführt wird, aber hauptsächlich auf Varianten von Solaris, Linux und Windows.

Konnte jemand erfolgreich Informationen wie den aktuell verwendeten Speicherplatz, die CPU-Auslastung und den im zugrunde liegenden Betriebssystem verwendeten Speicher extrahieren? Was ist mit dem, was die Java-App selbst verbraucht?

Am liebsten möchte ich diese Informationen ohne JNI erhalten.

Steve M.
quelle
3
In Bezug auf freien Speicher siehe stackoverflow.com/a/18366283/231397 ( Runtime.getRuntime().freeMemory()wie in der akzeptierten Antwort vorgeschlagen, gibt Ihnen NICHT die Menge an freiem Speicher.
Christian Fries

Antworten:

206

Sie können einige Informationen zum begrenzten Speicher von der Runtime-Klasse erhalten. Es ist wirklich nicht genau das, wonach Sie suchen, aber ich dachte, ich würde es der Vollständigkeit halber bereitstellen. Hier ist ein kleines Beispiel. Bearbeiten: Sie können Informationen zur Datenträgernutzung auch von der Klasse java.io.File abrufen. Für die Speicherplatznutzung ist Java 1.6 oder höher erforderlich.

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
quelle
7
Ich denke, "Gesamtspeicher, der derzeit von der JVM verwendet wird" ist etwas verwirrend. Der Javadoc sagt, dass die Funktion "die Gesamtmenge an Speicher zurückgibt, die derzeit für aktuelle und zukünftige Objekte verfügbar ist, gemessen in Bytes". Klingt eher nach verbleibendem und nicht verwendetem Speicher.
Dirk
@Dirk: Ich habe den Wortlaut aktualisiert, um Ihren Kommentar zu adressieren. Vielen Dank!
William Brendel
@LeonardoGaldioli: Ich kenne die Leistungsmerkmale dieser Klassen und Methoden nicht, aber ich wäre nicht überrascht, wenn sie nicht auf Geschwindigkeit optimiert wären. Andere Antworten erläutern, wie bestimmte Informationen mit JMX erfasst werden, was möglicherweise schneller ist.
William Brendel
15
Dies beantwortet die Frage nicht richtig. Alle diese Daten beziehen sich auf JVM und nicht auf das Betriebssystem ...
Alvaro
Ich weiß, dass dieses Thema ziemlich veraltet ist. ABER: Wenn Sie wirklich die Menge an CPU-Kernen benötigen, verwenden Sie diese Lösung nicht. Ich habe eine Dual-Core-CPU mit zwei Threads für jeden Kern. Die JVM gibt nicht die Hardwarekerne zurück, sondern die Softwarekerne / Threads.
F_Schmidt
95

Das Paket java.lang.management bietet Ihnen viel mehr Informationen als Runtime - zum Beispiel gibt es Ihnen Heap-Speicher ( ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()) getrennt von Nicht-Heap-Speicher ( ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage()).

Sie können auch Prozess der CPU - Auslastung (ohne eigenen JNI Code schreiben), aber Sie müssen das werfen , java.lang.management.OperatingSystemMXBeanum ein com.sun.management.OperatingSystemMXBean. Dies funktioniert unter Windows und Linux, ich habe es nicht anderswo getestet.

Beispiel: Rufen Sie die Methode get getCpuUsage () häufiger auf, um genauere Messwerte zu erhalten.

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
quelle
10
Um es zu kompilieren, ersetzen Sie die Umwandlung OperatingSystemMXBeanin com.sun.management.OperatingSystemMXBeanund setzen Sie alle Instanzen von getOperatingSystemMXBean()mit voran ManagementFactory.. Sie müssen alle Klassen entsprechend importieren.
Tmarthal
2
Ich bekomme CPU-Nutzung als 0 für alles. Ich habe die CPU-Verwendungsformel in cpuUsage = processCpuTime / systemTime geändert. Ich bekomme einen Wert für die CPU-Nutzung, den ich nicht verstehe.
Raj
Bedeutet 1.0 als Ergebnis von getCpuUsage, dass das System alle verfügbaren Prozessoren zu 100% verwendet?
user454322
2
Ich bekomme immer 0, wie @Raj sagte ... können Sie ein Beispiel für die Verwendung dieses Codes geben?
dm76
1
Versuchen Sie((double)( processCpuTime - lastProcessCpuTime )) / ((double)( systemTime - lastSystemTime ))
Anthony O.
43

Ich denke, die beste Methode ist die Implementierung der SIGAR-API von Hyperic . Es funktioniert für die meisten gängigen Betriebssysteme (fast alles Moderne) und ist sehr einfach zu handhaben. Die Entwickler reagieren sehr schnell auf ihre Foren und Mailinglisten. Mir gefällt auch, dass es GPL2 Apache lizenziert ist . Sie bieten auch in Java eine Menge Beispiele!

SIGAR == Systeminformations-, Erfassungs- und Berichterstellungstool.

Matt Cummings
quelle
2
@ Yohan - Sei nicht faul! Sie können dies herausfinden, indem Sie die verlinkte Webseite lesen . (Und es hängt davon ab, was Sie unter "plattformunabhängig" verstehen.)
Stephen C
2
@StephenC: Sigar verwendet DLL-Dateien, wodurch es plattformabhängig wird. Die übergeordnete API könnte in Java sein, es ist eine andere Geschichte
Zitronensaft
1
@Artificial_Intelligence ja, aber es bietet Bibliotheken (geschrieben in c) für die meisten gängigen Plattformen. Es ist nicht plattformabhängiger als das JVM selbst. Die übergeordnete Java-API sollte auf allen Plattformen konsistent sein.
Jeshurun
8
Sigar wird seit 2010 nicht mehr aktualisiert und scheint einen Fehler auf 64-Bit-Systemen zu haben: stackoverflow.com/questions/23405832/…
Alvaro
1
Und SIGAR führt auch zum Absturz der JVM (wenn auch nur zeitweise), aber ich bin sicher, dass Sie dieses Risiko in der Produktion nicht eingehen werden.
AKS
25

Es gibt ein Java-Projekt, das JNA verwendet (also keine nativen Bibliotheken zu installieren) und sich in der aktiven Entwicklung befindet. Es unterstützt derzeit Linux, OSX, Windows, Solaris und FreeBSD und bietet Informationen zu RAM, CPU, Akku und Dateisystem.

dB.
quelle
Keine native Bibliothek ist vielleicht irreführend. Das Projekt verwendet native Bibliotheken, auch wenn sie keine geschrieben haben, und Sie müssen anscheinend keine installieren.
Stephen C
1
Du hast recht. JNA verwendet libffi mit nativen Komponenten. Aber für alle Zwecke sieht es so aus, als gäbe es keine nativen Bibliotheken (definitiv keine, die installiert werden müssen).
dB.
@StephenC Obwohl das, was Sie sagen, korrekt ist, ist es irreführend, weil es dasselbe für rt.jar ist, das auch native Methoden aufruft. Der einzige Grund, warum sich Benutzer für native Methoden interessieren, besteht darin, dass sie diese kompilieren und / oder installieren müssen, was häufig eine nicht triviale Aufgabe ist. Da libffi so weit verbreitet, portiert und installiert ist, werden die Schwierigkeiten gemindert. Technisch gesehen haben Sie also Recht, aber praktisch spielt es keine Rolle.
rbp
@rbp - Es gibt noch einen weiteren Grund, warum erfahrene Java-Entwickler native Bibliotheken lieber meiden. Eine native Bibliothek mit Fehlern (einschließlich Thread-Sicherheitsproblemen oder Problemen mit der Speicherverwaltung) kann die Host-JVM destabilisieren. Dies ist kein "es spielt keine Rolle" Problem ....
Stephen C
@StephenC macht es mich erfahren genug , den Weblogic-Anwendungsserver erstellt zu haben ?
rbp
13

Für Fenster bin ich diesen Weg gegangen.

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

Hier ist der Link mit Details.

Yan Khonski
quelle
11

Sie können einige Informationen auf Systemebene abrufen System.getenv(), indem Sie den entsprechenden Umgebungsvariablennamen als Parameter übergeben. Zum Beispiel unter Windows:

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

Bei anderen Betriebssystemen unterscheiden sich das Vorhandensein / Fehlen und die Namen der relevanten Umgebungsvariablen.

Alexandr
quelle
1
Diese sind plattformabhängig, da sich die Variablennamen zwischen den Systemen unterscheiden. Der Oracle-Artikel zu Umgebungsvariablen sagt dies aus. Ich finde auch einen Weg, systemunabhängig zu werden.
Zitronensaft
Unter Linux (Ubuntu 17.10) gibt es nicht viele interessante Informationen zu Prozessoren in der Umgebung.
Pveentjer
8

Fügen Sie die OSHI-Abhängigkeit über maven hinzu:

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

Erhalten Sie eine verbleibende Batteriekapazität in Prozent:

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
quelle
OSHI verfügt über die meisten Informationen, die in den anderen Kommentaren beschrieben sind. Wenn möglich, wird JNA verwendet, um es über native OS-Aufrufe abzurufen.
Daniel Widdis
6

Schauen Sie sich die APIs an, die im Paket java.lang.management verfügbar sind . Beispielsweise:

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

Es gibt dort auch viele andere nützliche Dinge.

Mitarbeiter
quelle
2
OperatingSystemMXBean.getSystemLoadAverage () ist nicht in Windows implementiert, weil "es zu teuer ist"
MikeNereson
1
ThreadMXBean.getCurrentThreadCpuTime () gibt nur zurück, wie lange dieser Thread ausgeführt wurde. Nicht der Prozentsatz der CPU-Auslastung.
MikeNereson
5

Um Informationen zum Betriebssystem auf niedriger Ebene zu erhalten, können Sie normalerweise betriebssystemspezifische Befehle aufrufen, die Ihnen die gewünschten Informationen mit Runtime.exec () geben, oder Dateien wie / proc / * unter Linux lesen.

Peter Lawrey
quelle
5

Die CPU-Auslastung ist nicht einfach - java.lang.management über com.sun.management.OperatingSystemMXBean.getProcessCpuTime kommt dem nahe (siehe Patricks hervorragendes Code-Snippet oben), aber beachten Sie, dass es nur Zugriff auf die Zeit gibt, die die CPU in Ihrem Prozess verbracht hat. Es gibt keinen Aufschluss über die CPU-Zeit, die in anderen Prozessen verbracht wurde, oder sogar über die CPU-Zeit, die für Systemaktivitäten im Zusammenhang mit Ihrem Prozess aufgewendet wurde.

Zum Beispiel habe ich einen netzwerkintensiven Java-Prozess - es ist das einzige, was läuft und die CPU ist bei 99%, aber nur 55% davon werden als "Prozessor-CPU" gemeldet.

Lassen Sie mich nicht einmal mit "Load Average" anfangen, da es so gut wie nutzlos ist, obwohl es das einzige CPU-bezogene Element auf der MX-Bean ist. wenn nur die Sonne in ihrer gelegentlichen Weisheit etwas wie "getTotalCpuTime" aussetzen würde ...

Für eine ernsthafte CPU-Überwachung scheint das von Matt erwähnte SIGAR die beste Wahl zu sein.

Teilweise wolkig
quelle
4

Ein Windows, Sie können den systeminfoBefehl ausführen und seine Ausgabe beispielsweise mit dem folgenden Code abrufen:

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

Wenn Sie Jrockit VM verwenden, finden Sie hier eine andere Möglichkeit, die CPU-Auslastung der VM zu ermitteln. Runtime Bean kann Ihnen auch die CPU-Auslastung pro Prozessor geben. Ich habe dies nur unter Red Hat Linux verwendet, um die Leistung von Tomcat zu beobachten. Sie müssen JMX remote in Catalina.sh aktivieren, damit dies funktioniert.

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

Es befindet sich noch in der Entwicklung, aber Sie können jHardware bereits verwenden

Es ist eine einfache Bibliothek, die Systemdaten mit Java verschrottet. Es funktioniert sowohl unter Linux als auch unter 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
quelle
Schön, aber es werden Guava- und JNA-Versionen verwendet, die im Widerspruch zu meinen Anforderungen stehen (siehe z. B. GLASSFISH-21367 ).
lu_ko
Hallo, JNA wurde in der Version 0.8 von jHardware eingeführt. Es wird nur für Temperatur- und Sensordaten verwendet. Wenn Sie diese Informationen nicht benötigen, können Sie die Version 0.7 verwenden. Gleiches gilt für Guave. In diesem Fall müssen Sie die Version 0.6.3 verwenden.
profesor_falken
2

Ein einfacher Weg, um Informationen auf Betriebssystemebene abzurufen, und den ich auf meinem Mac getestet habe und der gut funktioniert:

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

Sie können viele relevante Kennzahlen des Betriebssystems finden Sie hier

Amandeep Singh
quelle
1

Hey, das kannst du mit Java / Com Integration machen. Durch den Zugriff auf WMI-Funktionen erhalten Sie alle Informationen.


quelle
0

Um den Systemlastdurchschnitt von 1 Minute, 5 Minuten und 15 Minuten innerhalb des Java-Codes zu erhalten, können Sie dies tun, indem Sie den Befehl cat /proc/loadavgwie folgt ausführen und interpretieren:

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

Und um den physischen Systemspeicher zu erhalten, indem Sie den Befehl ausführen free -mund ihn dann wie folgt interpretieren:

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
quelle