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.

Steve M.
źródło
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());
    }
  }
}
William Brendel
źródło
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();
        }
    }
}
Patrick Wilkes
źródło
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.

Matt Cummings
źródło
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.

dB.
źródło
Ż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.

Yan Khonski
źródło
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ć.

Alexandr
źródło
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));
}
Oleksii Kyslytsyn
źródło
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.

Staffan
źródło
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.

Peter Lawrey
źródło
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.

Częściowe zachmurzenie
źródło
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();
    }
}
BullyWiiPlaza
źródło
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");
petro
źródło
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());
//[...]
profesor_falken
źródło
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

Amandeep Singh
źródło
1

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


źródło
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);
krishna Prasad
źródło