Jak monitorować użycie procesora, pamięci i dysku komputera w Javie?


180

Chciałbym monitorować następujące informacje systemowe w Javie:

  • Bieżące użycie procesora ** (procent)
  • Dostępna pamięć * (wolna / całkowita)
  • Dostępne miejsce na dysku (wolne / ogółem)

    * Pamiętaj, że mam na myśli ogólną pamięć dostępną dla całego systemu, a nie tylko JVM.

Szukam rozwiązania wieloplatformowego (Linux, Mac i Windows), który nie będzie polegał na moim własnym kodzie wywołującym programy zewnętrzne lub używającym JNI. Chociaż są to realne opcje, wolałbym nie utrzymywać kodu specyficznego dla systemu operacyjnego, jeśli ktoś ma już lepsze rozwiązanie.

Jeśli dostępna jest darmowa biblioteka, która robi to w niezawodny sposób na wiele platform, byłoby świetnie (nawet jeśli wykonuje zewnętrzne wywołania lub sam kod macierzysty).

Wszelkie sugestie są mile widziane.

Aby to wyjaśnić, chciałbym uzyskać bieżące wykorzystanie procesora dla całego systemu, a nie tylko dla procesów Java.

Interfejs API SIGAR zapewnia wszystkie funkcje, których szukam w jednym pakiecie, więc jest to najlepsza jak dotąd odpowiedź na moje pytanie. Ponieważ jednak jest licencjonowany na licencji GPL, nie mogę go używać do moich pierwotnych celów (zamknięty produkt komercyjny). Możliwe, że Hyperic może licencjonować SIGAR do użytku komercyjnego, ale nie analizowałem tego. W przypadku moich projektów GPL zdecydowanie rozważę SIGAR w przyszłości.

Na moje obecne potrzeby skłaniam się w kierunku:

  • Do wykorzystania procesora OperatingSystemMXBean.getSystemLoadAverage() / OperatingSystemMXBean.getAvailableProcessors()(średnie obciążenie na procesor)
  • Dla pamięci OperatingSystemMXBean.getTotalPhysicalMemorySize()iOperatingSystemMXBean.getFreePhysicalMemorySize()
  • Dla miejsca na dysku File.getTotalSpace()iFile.getUsableSpace()

Ograniczenia:

getSystemLoadAverage()I przestrzeń dysku metody wysyłania zapytań są dostępne tylko w języku Java 6. Ponadto niektóre funkcje JMX nie mogą być dostępne dla wszystkich platform (czyli to doniesienia, że getSystemLoadAverage()wraca -1 w Windows).

Chociaż pierwotnie licencjonowany na licencji GPL, został zmieniony na Apache 2.0 , który ogólnie może być używany do zamkniętych produktów komercyjnych.


Aby to wyjaśnić, interfejs API sigar pobiera informacje o systemie. Jeśli chcesz uzyskać informacje o jvm, użyj JMX.
Matt Cummings,

SIGAR będący na licencji GPL nie wyklucza korzystania z niego, oznacza tylko, że musisz skontaktować się z autorami i poprosić o alternatywne licencje. Autorzy często chętnie przyjmują niewielką opłatę i zezwalają na komercyjne licencjonowanie.
Alec Thomas

7
Od wersji 1.6.4 SIGAR korzysta z licencji Apache.
Soundlink

czy wiesz, jak uzyskać obciążenie dla każdego procesora?
zcaudate

Odpowiedzi:


67

Zgodnie z tym, co wspomniałem w tym poście . Polecam korzystanie z interfejsu API SIGAR . Używam SIGAR API w jednej z moich własnych aplikacji i jest świetna. Przekonasz się, że jest stabilny, dobrze obsługiwany i pełen przydatnych przykładów. Jest open source z GPL 2 Apache 2.0. Sprawdź to. Mam wrażenie, że spełni twoje potrzeby.

Za pomocą Java i Sigar API można uzyskać pamięć, procesor, dysk, obciążenie średnie, informacje i dane interfejsu sieciowego, informacje o tabeli procesów, informacje o trasie itp.


14
Zachowaj ostrożność podczas korzystania z Sigara, na komputerach z procesorem x64 występują problemy ... stackoverflow.com/questions/23405832/ ... i wygląda na to, że biblioteka nie aktualizuje się od 2010 r.
Alvaro

56

Następująco podobno dostaje procesor i pamięć RAM. Zobacz ManagementFactory po więcej szczegółów.

import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

private static void printUsage() {
  OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();
  for (Method method : operatingSystemMXBean.getClass().getDeclaredMethods()) {
    method.setAccessible(true);
    if (method.getName().startsWith("get")
        && Modifier.isPublic(method.getModifiers())) {
            Object value;
        try {
            value = method.invoke(operatingSystemMXBean);
        } catch (Exception e) {
            value = e;
        } // try
        System.out.println(method.getName() + " = " + value);
    } // if
  } // for
}

3
Przykładowe dane wyjściowe dla powyższego kodu. Ten kod działa w Javie 1.5. getCommittedVirtualMemorySize = 28622848 getFreePhysicalMemorySize = 228462592 getFreeSwapSpaceSize = 1129848832 getProcessCpuTime = 390625000 getTotalPhysicalMemorySize = 2147483647 getTotalSwapSpaceSize = 4294967295
blak3r

AFAIK getProcessCpuTime = 390625000 to tylko czas działania tego wątku. Nie jest to zbyt przydatne do określania użycia procesora
MikeNereson

2
Nie jestem pewien, czy to naprawdę niezawodne. W systemie Windows XP z 4 GB pamięci fizycznej raportuje tylko 2 GB (testowane z Javą 6 i Javą 7). Niepoprawny jest także całkowity rozmiar wymiany.
Emmanuel Bourg

4
@EmmanuelBourg tylko dla dokumentowania dla osób, które widzą ten temat, jest związany z tym błąd .
Sérgio Michels,

2
Ta metoda działała świetnie do czasu Java 9, teraz generuje wyjątek java.lang.reflect.InaccessibleObjectException ze względu na nową strukturę sprawdzania dostępu, z której korzysta Java.
Thor Lancaster,

40

W JDK 1.7 możesz uzyskać użycie procesora i pamięci systemu com.sun.management.OperatingSystemMXBean. To jest inne niż java.lang.management.OperatingSystemMXBean.

long    getCommittedVirtualMemorySize()
Returns the amount of virtual memory that is guaranteed to be available to the running process in bytes, or -1 if this operation is not supported.

long    getFreePhysicalMemorySize()
Returns the amount of free physical memory in bytes.

long    getFreeSwapSpaceSize()
Returns the amount of free swap space in bytes.

double  getProcessCpuLoad()
Returns the "recent cpu usage" for the Java Virtual Machine process.

long    getProcessCpuTime()
Returns the CPU time used by the process on which the Java virtual machine is running in nanoseconds.

double  getSystemCpuLoad()
Returns the "recent cpu usage" for the whole system.

long    getTotalPhysicalMemorySize()
Returns the total amount of physical memory in bytes.

long    getTotalSwapSpaceSize()
Returns the total amount of swap space in bytes.

5
Wygląda na to, że to trafienie i chybienie. Uzyskiwanie -1 dla obciążenia procesora we FreeBSD 10 i OpenJDK 8.
cen

sprawdź to pytanie stackoverflow.com/q/19781087/1206998 . mówi, że skuteczne są pary. (uwaga: nie próbowałem)
Juh_

25

Działa to dla mnie idealnie bez żadnego zewnętrznego API, tylko natywna ukryta funkcja Java :)

import com.sun.management.OperatingSystemMXBean;
...
OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(
                OperatingSystemMXBean.class);
// What % CPU load this current JVM is taking, from 0.0-1.0
System.out.println(osBean.getProcessCpuLoad());

// What % load the overall system is at, from 0.0-1.0
System.out.println(osBean.getSystemCpuLoad());

Naprawdę uważam, że to najlepsza odpowiedź, działa na Linuksie, więc jestem szczęśliwy.
ArsenArsen

1
jakieś wskazówki, dlaczego drugie wywołanie pokazuje 0.0? W OpenJDK v8.
vorburger

Nie zapomnij: „import java.lang.management.ManagementFactory;”
Bernd

1
getProcessCpuLoad i getSystemCpuLoad zwracają -1 ze mnie. używam jdk 1.8
Burak Akyıldız

Nie ma metody uzyskania liczby wątków? Zastanawiam się tylko dlaczego?
djangofan

16

Zobacz ten bardzo szczegółowy artykuł: http://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarking#UsingaSuninternalclasstogetJVMCPUtime

Aby uzyskać procent wykorzystanego procesora, wystarczy kilka prostych obliczeń:

MBeanServerConnection mbsc = ManagementFactory.getPlatformMBeanServer();

OperatingSystemMXBean osMBean = ManagementFactory.newPlatformMXBeanProxy(
mbsc, ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME, OperatingSystemMXBean.class);

long nanoBefore = System.nanoTime();
long cpuBefore = osMBean.getProcessCpuTime();

// Call an expensive task, or sleep if you are monitoring a remote process

long cpuAfter = osMBean.getProcessCpuTime();
long nanoAfter = System.nanoTime();

long percent;
if (nanoAfter > nanoBefore)
 percent = ((cpuAfter-cpuBefore)*100L)/
   (nanoAfter-nanoBefore);
else percent = 0;

System.out.println("Cpu usage: "+percent+"%");

Uwaga: Musisz importować, com.sun.management.OperatingSystemMXBeana nie importować java.lang.management.OperatingSystemMXBean.


To jest naprawdę dobra odpowiedź. Wszystkie pozostałe techniki dają naprawdę dziwne i niewiarygodne wyniki, ale ta z pewnym uśrednianiem działała dla mnie jak urok.
Fractaly,

Kiedy czas procesora jest dłuższy niż czas, który upłynął (mam ponad 100%), czy jest to spowodowane wielowątkowością lub jak to zrozumieć?
Lukas Hanacek


6

Wiele z nich jest już dostępnych za pośrednictwem JMX. W Javie 5 JMX jest wbudowany i zawierają przeglądarkę konsoli JMX z JDK.

Możesz użyć JMX do ręcznego monitorowania lub wywołać komendy JMX z Javy, jeśli potrzebujesz tych informacji we własnym czasie wykonywania.



4
/* YOU CAN TRY THIS TOO */

import java.io.File;
 import java.lang.management.ManagementFactory;
// import java.lang.management.OperatingSystemMXBean;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.management.RuntimeMXBean;
 import java.io.*;
 import java.net.*;
 import java.util.*;
 import java.io.LineNumberReader;
 import java.lang.management.ManagementFactory;
import com.sun.management.OperatingSystemMXBean;
import java.lang.management.ManagementFactory;
import java.util.Random;



 public class Pragati
 {

     public static void printUsage(Runtime runtime)
     {
     long total, free, used;
     int mb = 1024*1024;

     total = runtime.totalMemory();
     free = runtime.freeMemory();
     used = total - free;
     System.out.println("\nTotal Memory: " + total / mb + "MB");
     System.out.println(" Memory Used: " + used / mb + "MB");
     System.out.println(" Memory Free: " + free / mb + "MB");
     System.out.println("Percent Used: " + ((double)used/(double)total)*100 + "%");
     System.out.println("Percent Free: " + ((double)free/(double)total)*100 + "%");
    }
    public static void log(Object message)
         {
            System.out.println(message);
         }

        public static int calcCPU(long cpuStartTime, long elapsedStartTime, int cpuCount)
        {
             long end = System.nanoTime();
             long totalAvailCPUTime = cpuCount * (end-elapsedStartTime);
             long totalUsedCPUTime = ManagementFactory.getThreadMXBean().getCurrentThreadCpuTime()-cpuStartTime;
             //log("Total CPU Time:" + totalUsedCPUTime + " ns.");
             //log("Total Avail CPU Time:" + totalAvailCPUTime + " ns.");
             float per = ((float)totalUsedCPUTime*100)/(float)totalAvailCPUTime;
             log( per);
             return (int)per;
        }

        static boolean isPrime(int n)
        {
     // 2 is the smallest prime
            if (n <= 2)
            {
                return n == 2;
            }
     // even numbers other than 2 are not prime
            if (n % 2 == 0)
            {
                return false;
            }
     // check odd divisors from 3
     // to the square root of n
         for (int i = 3, end = (int)Math.sqrt(n); i <= end; i += 2)
         {
            if (n % i == 0)
         {
         return false;
        }
        }
 return true;
}
    public static void main(String [] args)
    {
            int mb = 1024*1024;
            int gb = 1024*1024*1024;
             /* PHYSICAL MEMORY USAGE */
             System.out.println("\n**** Sizes in Mega Bytes ****\n");
            com.sun.management.OperatingSystemMXBean operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
            //RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
            //operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
            com.sun.management.OperatingSystemMXBean os = (com.sun.management.OperatingSystemMXBean)
            java.lang.management.ManagementFactory.getOperatingSystemMXBean();
            long physicalMemorySize = os.getTotalPhysicalMemorySize();
            System.out.println("PHYSICAL MEMORY DETAILS \n");
            System.out.println("total physical memory : " + physicalMemorySize / mb + "MB ");
            long physicalfreeMemorySize = os.getFreePhysicalMemorySize();
            System.out.println("total free physical memory : " + physicalfreeMemorySize / mb + "MB");
            /* DISC SPACE DETAILS */
            File diskPartition = new File("C:");
            File diskPartition1 = new File("D:");
            File diskPartition2 = new File("E:");
            long totalCapacity = diskPartition.getTotalSpace() / gb;
            long totalCapacity1 = diskPartition1.getTotalSpace() / gb;
            double freePartitionSpace = diskPartition.getFreeSpace() / gb;
            double freePartitionSpace1 = diskPartition1.getFreeSpace() / gb;
            double freePartitionSpace2 = diskPartition2.getFreeSpace() / gb;
            double usablePatitionSpace = diskPartition.getUsableSpace() / gb;
            System.out.println("\n**** Sizes in Giga Bytes ****\n");
            System.out.println("DISC SPACE DETAILS \n");
            //System.out.println("Total C partition size : " + totalCapacity + "GB");
            //System.out.println("Usable Space : " + usablePatitionSpace + "GB");
            System.out.println("Free Space in drive C: : " + freePartitionSpace + "GB");
            System.out.println("Free Space in drive D:  : " + freePartitionSpace1 + "GB");
            System.out.println("Free Space in drive E: " + freePartitionSpace2 + "GB");
            if(freePartitionSpace <= totalCapacity%10 || freePartitionSpace1 <= totalCapacity1%10)
            {
                System.out.println(" !!!alert!!!!");
            }
            else
                System.out.println("no alert");

            Runtime runtime;
            byte[] bytes;
            System.out.println("\n \n**MEMORY DETAILS  ** \n");
            // Print initial memory usage.
            runtime = Runtime.getRuntime();
            printUsage(runtime);

            // Allocate a 1 Megabyte and print memory usage
            bytes = new byte[1024*1024];
            printUsage(runtime);

            bytes = null;
            // Invoke garbage collector to reclaim the allocated memory.
            runtime.gc();

            // Wait 5 seconds to give garbage collector a chance to run
            try {
            Thread.sleep(5000);
            } catch(InterruptedException e) {
            e.printStackTrace();
            return;
            }

            // Total memory will probably be the same as the second printUsage call,
            // but the free memory should be about 1 Megabyte larger if garbage
            // collection kicked in.
            printUsage(runtime);
            for(int i = 0; i < 30; i++)
                     {
                         long start = System.nanoTime();
                        // log(start);
                        //number of available processors;
                         int cpuCount = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors();
                         Random random = new Random(start);
                         int seed = Math.abs(random.nextInt());
                         log("\n \n CPU USAGE DETAILS \n\n");
                         log("Starting Test with " + cpuCount + " CPUs and random number:" + seed);
                         int primes = 10000;
                         //
                         long startCPUTime = ManagementFactory.getThreadMXBean().getCurrentThreadCpuTime();
                         start = System.nanoTime();
                         while(primes != 0)
                         {
                            if(isPrime(seed))
                            {
                                primes--;
                            }
                            seed++;

                        }
                         float cpuPercent = calcCPU(startCPUTime, start, cpuCount);
                         log("CPU USAGE : " + cpuPercent + " % ");


                         try
                         {
                             Thread.sleep(1000);
                         }
                         catch (InterruptedException e) {}
        }

            try
            {
                Thread.sleep(500);
            }`enter code here`
            catch (Exception ignored) { }
        }
    }

4

Poniższy kod to tylko Linux (może Unix), ale działa w prawdziwym projekcie.

    private double getAverageValueByLinux() throws InterruptedException {
    try {

        long delay = 50;
        List<Double> listValues = new ArrayList<Double>();
        for (int i = 0; i < 100; i++) {
            long cput1 = getCpuT();
            Thread.sleep(delay);
            long cput2 = getCpuT();
            double cpuproc = (1000d * (cput2 - cput1)) / (double) delay;
            listValues.add(cpuproc);
        }
        listValues.remove(0);
        listValues.remove(listValues.size() - 1);
        double sum = 0.0;
        for (Double double1 : listValues) {
            sum += double1;
        }
        return sum / listValues.size();
    } catch (Exception e) {
        e.printStackTrace();
        return 0;
    }

}

private long getCpuT throws FileNotFoundException, IOException {
    BufferedReader reader = new BufferedReader(new FileReader("/proc/stat"));
    String line = reader.readLine();
    Pattern pattern = Pattern.compile("\\D+(\\d+)\\D+(\\d+)\\D+(\\d+)\\D+(\\d+)")
    Matcher m = pattern.matcher(line);

    long cpuUser = 0;
    long cpuSystem = 0;
    if (m.find()) {
        cpuUser = Long.parseLong(m.group(1));
        cpuSystem = Long.parseLong(m.group(3));
    }
    return cpuUser + cpuSystem;
}

1
Właśnie tego szukałem, ale w kodzie brakuje wzorca REGEX do znajdowania informacji o procesorze z / proc / stat
Donal Tobin

jaki jest wzór?
HCarrasko

3

Utwórz plik wsadowy „Pc.bat” jako, typeperf -sc 1 „\ mukit \ procesor (_ Razem) \ %% Czas procesora”

Możesz użyć klasy MProcess,

/ *
 * Md. Mukit Hasan
 * CSE-JU, 35
 ** / import java . io . *;

MProcessor klasy publicznej {

public MProcessor() { String s; try { Process ps = Runtime.getRuntime().exec("Pc.bat"); BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream())); while((s = br.readLine()) != null) { System.out.println(s); } } catch( Exception ex ) { System.out.println(ex.toString()); } }

}

Następnie po manipulacji ciągiem uzyskuje się użycie procesora. Możesz użyć tego samego procesu do innych zadań.

- Muit Hasan


1
dla mnie (Win XP) właściwy wiersz poleceń brzmiał: typeperf "\processor(_total)\% processor time"Jeśli umieścisz go w pliku wsadowym, użyj %% zamiast%. Użyłem technet.microsoft.com/en-us/library/bb490960.aspx .
tutejszy
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.