Как я могу отслеживать использование процессора, памяти и диска компьютера в Java?

180

Я хотел бы отслеживать следующую системную информацию в Java:

  • Текущее использование процессора ** (в процентах)
  • Доступная память * (бесплатно / всего)
  • Свободное место на диске (бесплатно / всего)

    * Обратите внимание, что я имею в виду общую память, доступную для всей системы, а не только для JVM.

Я ищу кроссплатформенное решение (Linux, Mac и Windows), которое не зависит от моего собственного кода, вызывающего внешние программы или использующего JNI. Хотя это жизнеспособные варианты, я бы предпочел не поддерживать специфичный для ОС код, если у кого-то уже есть лучшее решение.

Если есть бесплатная библиотека, которая делает это надежным, кроссплатформенным способом, это было бы замечательно (даже если она выполняет внешние вызовы или использует сам нативный код).

Любые предложения очень ценятся.

Чтобы уточнить, я хотел бы получить текущее использование процессора для всей системы, а не только для процесса (ов) Java.

API SIGAR предоставляет все функции, которые я ищу в одном пакете, так что это лучший ответ на мой вопрос на данный момент. Однако из-за того, что он лицензирован по лицензии GPL, я не могу использовать его в своих первоначальных целях (закрытый источник, коммерческий продукт). Возможно, что Hyperic может лицензировать SIGAR для коммерческого использования, но я не рассматривал это. Что касается моих проектов GPL, я обязательно рассмотрю SIGAR в будущем.

Для моих текущих потребностей я склоняюсь к следующему:

  • Для использования процессора OperatingSystemMXBean.getSystemLoadAverage() / OperatingSystemMXBean.getAvailableProcessors()(средняя загрузка на процессор)
  • Для памяти OperatingSystemMXBean.getTotalPhysicalMemorySize()иOperatingSystemMXBean.getFreePhysicalMemorySize()
  • Для дискового пространства, File.getTotalSpace()иFile.getUsableSpace()

Ограничения:

getSystemLoadAverage()И методы пространства Выполнение запросов диска доступны только в Java 6. Кроме того , некоторые функциональные возможности JMX не могут быть доступны для всех платформ (т.е. было сообщено , что getSystemLoadAverage()возвращает -1 на Windows).

Хотя изначально он был лицензирован по лицензии GPL, он был изменен на Apache 2.0 , который обычно можно использовать для коммерческих продуктов с закрытым исходным кодом.

Дэвид Кроу
источник
Чтобы уточнить, Sigar API получает информацию о вашей системе. Если вам нужна информация о jvm, используйте JMX.
Мэтт Каммингс
Наличие SIGAR под лицензией GPL не исключает возможности его использования, а просто означает, что вам нужно связаться с авторами и запросить альтернативное лицензирование. Авторы часто рады принять небольшую плату и разрешить коммерческое лицензирование.
Алек Томас
7
Начиная с версии 1.6.4 SIGAR использует лицензию Apache.
Soundlink
Вы знаете, как получить нагрузку для каждого отдельного процессора?
zcaudate

Ответы:

67

В соответствии с тем, что я упоминал в этом посте . Я рекомендую вам использовать SIGAR API . Я использую SIGAR API в одном из своих собственных приложений, и это здорово. Вы найдете его стабильным, хорошо поддерживаемым и полным полезных примеров. Это с открытым исходным кодом с лицензией Apache 2.0 GPL 2 . Проверьте это. У меня есть чувство, что оно будет соответствовать вашим потребностям.

Используя Java и Sigar API, вы можете получить память, процессор, диск, среднюю загрузку, информацию и метрики сетевого интерфейса, информацию таблицы процессов, информацию о маршруте и т. Д.

Мэтт Каммингс
источник
14
Будьте осторожны при использовании Sigar, на x64-машинах возникают проблемы ... stackoverflow.com/questions/23405832/… и, похоже, библиотека не обновляется с 2010 года
Alvaro
56

Следующее, якобы, дает вам процессор и оперативную память. См. ManagementFactory для более подробной информации.

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
Пример вывода для кода выше. Этот код работает на Java 1.5. getCommittedVirtualMemorySize = 28622848 getFreePhysicalMemorySize = 228462592 getFreeSwapSpaceSize = 1129848832 getProcessCpuTime = 390625000 getTotalPhysicalMemorySize = 2147483647 getTotalSwapSpaceSize = 4294967295
blak3r
AFAIK getProcessCpuTime = 390625000 - это только продолжительность работы этого потока. Это не очень полезно для определения использования процессора
MikeNereson
2
Не уверен, что это на самом деле надежно. В Windows XP с 4 ГБ физической памяти он сообщает только о 2 ГБ (протестировано с Java 6 и Java 7). Общий размер свопа также неверен.
Эммануэль Бур
4
@ EmmanuelBourg, просто чтобы документировать для людей, которые видят эту тему, есть ошибка, связанная с этим.
Сержио Михельс
2
Этот метод прекрасно работал до Java 9, теперь он генерирует исключение java.lang.reflect.InaccessibleObjectException из-за новой инфраструктуры проверки доступа, используемой Java.
Тор Ланкастер
40

В JDK 1.7 вы можете получить системный процессор и использование памяти через com.sun.management.OperatingSystemMXBean. Это отличается от 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.
Gp2you
источник
5
Похоже, что это хит и мисс. Получение -1 для загрузки процессора во FreeBSD 10 и OpenJDK 8.
cen
проверьте этот вопрос stackoverflow.com/q/19781087/1206998 . это говорит о том, что для эффективной пары требуется пара секунд. (примечание: я не пробовал)
Juh_
25

Это прекрасно работает без какого-либо внешнего API, просто скрытая функция 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());
bizzr3
источник
Я честно считаю, что это лучший ответ, работает на Linux, так что я счастлив, парень.
ArsenArsen
1
любая подсказка, почему второй вызов показывает 0.0? На OpenJDK v8.
vorburger
Не забудьте: "импортировать java.lang.management.ManagementFactory;"
Бернд
1
getProcessCpuLoad и getSystemCpuLoad возвращают -1 от меня. Я использую JDK 1,8
Бурак Акыылдыз
У него нет метода, чтобы получить количество потоков? Просто интересно почему?
Джангофан
16

Взгляните на эту очень подробную статью: http://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarking#UsingaSuninternalclasstogetJVMCPUtime

Чтобы получить процент использования процессора, все, что вам нужно, это несколько простых математических выражений:

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

Примечание: вы должны импортировать, com.sun.management.OperatingSystemMXBeanа не java.lang.management.OperatingSystemMXBean.

ludovicc
источник
Это действительно хороший ответ. Все остальные методы дают действительно странные и ненадежные результаты, но этот метод с некоторым усреднением по трейлингу сработал для меня как обаяние.
Фрактальный
Когда время процессора превышает истекшее время (я получаю более 100%), это только из-за многопоточности или как это понять?
Лукас Ханачек
8

Для дискового пространства, если у вас есть Java 6, вы можете использовать методы FileTotalSpace и getFreeSpace в File. Если вы не на Java 6, я думаю, что вы можете использовать Apache Commons IO, чтобы получить некоторые из них.

Я не знаю ни одного кроссплатформенного способа получить использование процессора или памяти, я боюсь.

Мэтт Шеппард
источник
6

Многое из этого уже доступно через JMX. В Java 5 встроен JMX, и он включает в себя просмотрщик консоли JMX с JDK.

Вы можете использовать JMX для мониторинга вручную или вызывать команды JMX из Java, если вам нужна эта информация во время выполнения.

Джейсон Коэн
источник
6

Принятый ответ в 2008 году рекомендовал SIGAR. Однако, как говорится в комментарии от 2014 года (@Alvaro):

Будьте осторожны при использовании Sigar, на x64-машинах возникают проблемы ... Сбой Sigar 1.6.4: EXCEPTION_ACCESS_VIOLATION, и, похоже, библиотека не обновляется с 2010 года

Я рекомендую использовать https://github.com/oshi/oshi

Или ответ, упомянутый выше .

OhadR
источник
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) { }
        }
    }
Pragati
источник
4

Следующий код предназначен только для Linux (возможно, Unix), но он работает в реальном проекте.

    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
На самом деле это то, что я искал, но в коде отсутствует шаблон REGEX для поиска информации о процессоре из / proc / stat
Donal Tobin
что такое шаблон ??
HCarrasko
3

Создайте пакетный файл "Pc.bat" как, введитеperper -sc 1 "\ mukit \ processor (_Total) \ %% Processor Time"

Вы можете использовать класс MProcess,

/ *
 * Md. Мукит Хасан
 * CSE-JU, 35
 ** / импорт Java . io . *;

открытый класс MProcessor {

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

}

Затем, после некоторой манипуляции со строками, вы получаете использование процессора. Вы можете использовать тот же процесс для других задач.

- Мукит Хасан

Мд. Мукит Хасан
источник
1
для меня (Win XP) правильная командная строка была: typeperf "\processor(_total)\% processor time"Если вы поместите ее в командный файл, используйте %% вместо%. Я использовал technet.microsoft.com/en-us/library/bb490960.aspx .
tutejszy