Uzyskaj informacje o systemie na poziomie systemu operacyjnego


232

Obecnie tworzę aplikację Java, która może być uruchamiana na wielu różnych platformach, ale przede wszystkim w wersjach Solaris, Linux i Windows.

Czy ktoś był w stanie z powodzeniem wyodrębnić informacje, takie jak bieżące używane miejsce na dysku, wykorzystanie procesora i pamięci w podstawowym systemie operacyjnym? A co z konsumowaniem samej aplikacji Java?

Najlepiej byłoby uzyskać te informacje bez korzystania z JNI.


3
Jeśli chodzi o wolną pamięć, patrz stackoverflow.com/a/18366283/231397 ( Runtime.getRuntime().freeMemory()zgodnie z sugestią w przyjętej odpowiedzi NIE daje ci ilości wolnej pamięci.
— Christian Fries

Odpowiedzi:


206

Możesz uzyskać pewne ograniczone informacje o pamięci z klasy Runtime. To naprawdę nie jest dokładnie to, czego szukasz, ale pomyślałem, że zapewnię to dla kompletności. Oto mały przykład. Edycja: Możesz również uzyskać informacje o użyciu dysku z klasy java.io.File. Wykorzystanie miejsca na dysku wymaga Java 1.6 lub wyższej.

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
Myślę, że „Całkowita pamięć obecnie używana przez JVM” jest nieco myląca. Javadoc mówi, które zwraca funkcja „Całkowita ilość pamięci aktualnie dostępne dla obecnych i przyszłych obiektów, mierzona w bajtach.” Brzmi bardziej jak pozostała pamięć i nieużywana.
— Dirk

@Dirk: Zaktualizowałem sformułowanie, aby uwzględnić Twój komentarz. Dzięki!
— William Brendel

@LeonardoGaldioli: Nie znam charakterystyki wydajności tych klas i metod, ale nie zdziwiłbym się, gdyby nie były zoptymalizowane pod kątem szybkości. Inne odpowiedzi wyjaśniają, jak zbierać określone informacje za pomocą JMX, co może być szybsze.
— William Brendel

15
To nie odpowiada poprawnie na pytanie. Wszystkie te dane odnoszą się do JVM, a nie do systemu operacyjnego ...
— Alvaro

Wiem, że ten temat jest dość przestarzały. ALE: Jeśli naprawdę potrzebujesz ilości rdzeni procesora, nie używaj tego rozwiązania. Mam dwurdzeniowy procesor z dwoma wątkami dla każdego rdzenia. JVM nie zwraca rdzeni sprzętowych, a raczej rdzeni / wątków oprogramowania.
— F_Schmidt

95

Java.lang.management pakiet nie daje o wiele więcej informacji niż Runtime - na przykład to daje pamięć sterty ( ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()) oddzielić od pamięci spoza sterty ( ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage()).

Można również uzyskać użycie procesora proces (bez pisania własnego kodu JNI), ale trzeba rzucać java.lang.management.OperatingSystemMXBeanDo com.sun.management.OperatingSystemMXBean. Działa to w systemach Windows i Linux, nie testowałem go gdzie indziej.

Na przykład ... częściej wywoływaj metodę getCpuUsage (), aby uzyskać dokładniejsze odczyty.

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
Aby uzyskać go skompilować, wymienić obsadę OperatingSystemMXBeando com.sun.management.OperatingSystemMXBeani poprzedzić wszystkie wystąpienia getOperatingSystemMXBean()z ManagementFactory.. Musisz odpowiednio zaimportować wszystkie klasy.
— tmarthal

2
Otrzymuję użycie procesora jako 0 dla wszystkiego. Zmieniłem formułę użycia procesora na cpuUsage = processCpuTime / systemTime. Otrzymuję wartość dla użycia procesora, której nie rozumiem.
— Raj,

Czy wynik 1,0getCpuUsage oznacza, że ​​system używa wszystkich dostępnych procesorów w 100%?
— user454322

2
Zawsze dostaję 0, jak powiedział @Raj ... czy możesz podać przykład użycia tego kodu?
— dm76

1
Spróbuj((double)( processCpuTime - lastProcessCpuTime )) / ((double)( systemTime - lastSystemTime ))
— Anthony O.

43

Myślę, że najlepszą metodą jest implementacja interfejsu API SIGAR przez Hyperic . Działa z większością głównych systemów operacyjnych (prawie wszystko, co nowoczesne) i jest bardzo łatwy w obsłudze. Deweloperzy reagują bardzo szybko na swoich forach i listach dyskusyjnych. Podoba mi się również, że jest licencjonowany na GPL2 Apache . Podają też mnóstwo przykładów w Javie!

SIGAR == Informacje o systemie, narzędzie do gromadzenia i raportowania.


2
@Yohan - Nie bądź leniwy! Możesz to sprawdzić, czytając połączoną stronę internetową. (I zależy to od tego, co rozumiesz przez „niezależny od platformy”.)
— Stephen C

2
@StephenC: Sigar używa plików .dll, co czyni go zależnym od platformy. Interfejs API wyższego poziomu może być w Javie, to inna historia
— Lemon Juice

1
@Artificial_Intelligence tak, ale zapewnia biblioteki (napisane w c) dla najpopularniejszych platform. Nie jest bardziej zależny od platformy niż sam Jvm. Interfejs API Java wyższego poziomu powinien być spójny na wszystkich platformach.
— Jeshurun

8
Sigar nie jest aktualizowany od 2010 roku i wydaje się, że ma błąd w systemach 64-bitowych: stackoverflow.com/questions/23405832/…
— Alvaro

1
SIGAR powoduje także awarię JVM (choć sporadycznie), ale jestem pewien, że nie podejmiesz tego ryzyka podczas produkcji.
— AKS

25

Istnieje projekt Java, który korzysta z JNA (więc nie ma bibliotek rodzimych do zainstalowania) i jest w fazie rozwoju. Obecnie obsługuje Linux, OSX, Windows, Solaris i FreeBSD i zapewnia informacje o pamięci RAM, procesorze, baterii i systemie plików.


Żadne rodzime biblioteki nie są chyba mylące. Projekt korzysta z bibliotek natywnych, nawet jeśli jeszcze ich nie napisał i najwyraźniej nie trzeba ich instalować.
— Stephen C

1
Masz rację. JNA używa libffi, który ma natywne komponenty. Ale do wszystkich celów wygląda na to, że nie ma natywnych bibliotek (zdecydowanie żadnych do zainstalowania).
— dB.

@StephenC, chociaż to, co mówisz, jest dokładne, wprowadza w błąd, ponieważ jest takie samo dla rt.jar, który wywołuje również metody natywne. jedynym powodem, dla którego ludzie interesują się metodami natywnymi, jest to, że muszą je skompilować i / lub zainstalować, co często jest nietrywialnym zadaniem. Ponieważ libffi jest tak szeroko adoptowane, przenoszone i instalowane, łagodzi to trudności. więc technicznie masz rację, ale praktycznie nie ma to znaczenia.
— rbp

@rbp - Istnieje jeszcze jeden powód, dla którego doświadczeni programiści Java wolą unikać bibliotek natywnych. Natywna biblioteka zawierająca błędy (w tym problemy z bezpieczeństwem wątków lub problemy z zarządzaniem pamięcią) może zdestabilizować maszynę JVM hosta. To nie jest „nie ma znaczenia” problem ....
— Stephen C

@StephenC czy posiadanie serwera aplikacji weblogic sprawia, że ​​jestem wystarczająco doświadczony ?
— rbp

13

W przypadku systemu Windows poszedłem w ten sposób.

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

Oto link ze szczegółami.


11

Możesz uzyskać pewne informacje na poziomie systemu System.getenv(), używając , przekazując odpowiednią nazwę zmiennej środowiskowej jako parametr. Na przykład w systemie Windows:

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

W przypadku innych systemów operacyjnych obecność / brak i nazwy odpowiednich zmiennych środowiskowych będą się różnić.


1
Zależą one od platformy, ponieważ nazwy zmiennych różnią się w zależności od systemu. Artykuł Oracle na temat zmiennych środowiskowych mówi o tym. Znajduję również sposób na uzyskanie niezależności systemu.
— Sok z cytryny,

Pod Linuksem (Ubuntu 17.10) nie ma zbyt wielu interesujących informacji dotyczących procesorów w środowisku.
— pveentjer

8

Dodaj zależność OSHI przez maven:

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

Uzyskaj pozostałą pojemność baterii w procentach:

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 ma większość informacji opisanych w innych komentarzach. Używa JNA, aby uzyskać go za pośrednictwem natywnych wywołań systemu operacyjnego, jeśli to możliwe.
— Daniel Widdis,

6

Zobacz interfejsy API dostępne w pakiecie java.lang.management . Na przykład:

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

Jest tam również wiele innych przydatnych rzeczy.


2
OperatingSystemMXBean.getSystemLoadAverage () nie jest zaimplementowany w systemie Windows, ponieważ „jest zbyt drogi”
— MikeNereson

1
ThreadMXBean.getCurrentThreadCpuTime () zwraca tylko czas działania tego wątku. Nie procent wykorzystania procesora.
— MikeNereson

5

Zwykle w celu uzyskania informacji o niskim poziomie systemu operacyjnego można wywoływać specyficzne dla systemu operacyjnego polecenia, które dostarczają żądane informacje za pomocą Runtime.exec () lub odczytywać pliki takie jak / proc / * w systemie Linux.


5

Użycie procesora nie jest proste - java.lang.management poprzez com.sun.management.OperatingSystemMXBean.getProcessCpuTime jest blisko (patrz doskonały fragment kodu Patricka powyżej), ale pamiętaj, że daje on dostęp tylko do czasu, jaki procesor spędził w twoim procesie. nie powie ci o czasie procesora spędzonym na innych procesach, ani nawet czasie procesora poświęconym na działania systemowe związane z twoim procesem.

na przykład mam proces Java wymagający intensywnej pracy sieci - to jedyna działająca rzecz, a procesor ma 99%, ale tylko 55% z tego jest zgłaszane jako „procesor procesora”.

nawet nie zaczynaj od „przeciętnego obciążenia”, ponieważ jest to prawie bezużyteczne, mimo że jest to jedyny związany z procesorem element na fasoli MX. gdyby tylko słońce w swojej sporadycznej mądrości ujawniło coś takiego jak „getTotalCpuTime” ...

do poważnego monitorowania procesora SIGAR wspomniany przez Matta wydaje się najlepszym wyborem.


4

Włącz Windows, możesz uruchomić systeminfopolecenie i pobrać jego dane wyjściowe, na przykład za pomocą następującego kodu:

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

Jeśli używasz Jrockit VM, oto inny sposób uzyskania wykorzystania procesora VM. Środowisko wykonawcze może również zapewnić obciążenie procesora na procesor. Użyłem tego tylko w Red Hat Linux do obserwowania wydajności Tomcat. Aby to zadziałało, musisz włączyć JMX remote w catalina.sh.

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

Jest wciąż w fazie rozwoju, ale możesz już używać jHardware

Jest to prosta biblioteka, która usuwa dane systemowe za pomocą Java. Działa zarówno w systemie Linux, jak i 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());
//[...]

Fajnie, ale używa wersji Guava i JNA, które są w konflikcie z moimi potrzebami (np. Patrz GLASSFISH-21367 ).
— lu_ko

Witaj, JNA została wprowadzona w wersji 0.8 jHardware. Służy wyłącznie do danych temperatury i czujników. Jeśli nie potrzebujesz tych informacji, możesz użyć wersji 0.7. To samo dotyczy Guawy. W takim przypadku będziesz musiał użyć wersji 0.6.3.
— profesor_falken

2

Jeden prosty sposób, za pomocą którego można uzyskać informacje o poziomie systemu operacyjnego, i przetestowałem na moim Macu, który działa dobrze:

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

Można znaleźć wiele odpowiednich metryk systemu operacyjnego tutaj


1

Hej, możesz to zrobić dzięki integracji java / com. Uzyskując dostęp do funkcji WMI, możesz uzyskać wszystkie informacje.


0

Aby uzyskać obciążenie systemu średnio 1 minutę, 5 minut i 15 minut wewnątrz kodu Java, możesz to zrobić, wykonując polecenie, cat /proc/loadavgużywając i interpretując go jak poniżej:

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

Aby uzyskać fizyczną pamięć systemową , wykonując polecenie, free -ma następnie interpretując go jak poniżej:

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);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.