Как в Java контролировать использование ЦП, памяти и диска компьютера?

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

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

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

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

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

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

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

SIGAR API предоставляет все функции, которые я ищу, в одном пакете, так что это пока лучший ответ на мой вопрос. Однако, поскольку он находится под лицензией 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.

Matt Cummings 08.09.2008 03:09

SIGAR под лицензией GPL не препятствует вам использовать ее, это просто означает, что вы должны связаться с авторами и запросить альтернативное лицензирование. Авторы часто рады принять небольшую плату и разрешить коммерческое лицензирование.

Alec Thomas 28.11.2008 20:04

Начиная с версии 1.6.4 SIGAR использует лицензию Apache.

Soundlink 31.01.2011 14:17

вы знаете, как получить нагрузку для каждого отдельного процессора?

zcaudate 12.09.2012 05:27
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
188
4
272 869
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

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

Боюсь, что я не знаю какого-либо кроссплатформенного способа получить использование ЦП или использование памяти.

Следующее предположительно дает вам процессор и оперативную память. Подробнее см. УправлениеЗавод.

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
}

Пример вывода для приведенного выше кода. Этот код действительно работает на Java 1.5. getCommittedVirtualMemorySize = 28622848 getFreePhysicalMemorySize = 228462592 getFreeSwapSpaceSize = 1129848832 getProcessCpuTime = 390625000 getTotalPhysicalMemorySize = 2147483647 getTotalSwap294967Space

blak3r 20.05.2009 09:41

AFAIK getProcessCpuTime = 390625000 - это только то, как долго этот поток был запущен. Это не очень полезно для определения использования процессора.

MikeNereson 14.07.2009 19:35

Не уверен, что это действительно надежно. В Windows XP с 4 ГБ физической памяти отображается только 2 ГБ (проверено с Java 6 и Java 7). Общий размер свопа также неверен.

Emmanuel Bourg 28.07.2011 21:59

@EmmanuelBourg, просто чтобы задокументировать для людей, которые видят эту тему, есть ошибка, связанный с этим.

user800014 13.09.2012 21:22

Этот метод отлично работал до Java 9, теперь он выдает исключение java.lang.reflect.InaccessibleObjectException из-за новой инфраструктуры проверки доступа, которую использует Java.

Thor Lancaster 26.07.2019 03:14
Ответ принят как подходящий

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

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

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

Alvaro 01.05.2014 14:46

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

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

Следующий код предназначен только для 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;
}

На самом деле это то, что я искал, но в коде отсутствует шаблон REGEX для поиска информации о процессоре из файла / proc / stat.

Donal Tobin 07.03.2012 13:05

какой узор ??

HCarrasko 27.01.2015 18:04

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

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

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

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

}

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

- Мукит Хасан

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

tutejszy 21.01.2013 19:06

Взгляните на эту очень подробную статью: 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.

Это действительно хороший ответ. Все остальные методы дают действительно странные и ненадежные результаты, но этот с некоторым скользящим усреднением сработал для меня как прелесть.

Fractaly 13.08.2019 00:26

Когда время процессора выше, чем прошедшее время (я получаю более 100%), это просто из-за многопоточности или как это понять?

Lukas Hanacek 03.03.2020 11:04

Ссылка больше не работает, какой пакет MBeanServerConnection?

RonPringadi 18.09.2020 03:02

В 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.

Похоже, это хит и промах. Получение -1 для загрузки процессора в FreeBSD 10 и OpenJDK 8.

cen 18.02.2016 19:13

проверьте этот вопрос stackoverflow.com/q/19781087/1206998. в нем говорится, что для достижения эффекта требуется пара секунд. (примечание: я не пробовал)

Juh_ 25.05.2018 17:02

/* 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) { }
        }
    }

Это отлично работает для меня без какого-либо внешнего 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());

Я честно считаю, что это лучший ответ, работает в Linux, так что я счастлив, парень.

ArsenArsen 04.10.2016 23:46

любая подсказка, почему второй вызов показывает 0,0? В OpenJDK v8.

vorburger 10.07.2017 14:33

Не забывайте: «import java.lang.management.ManagementFactory;»

Bernd 06.01.2018 12:46

getProcessCpuLoad и getSystemCpuLoad возвращают -1 от меня. Я использую jdk 1.8

Burak Akyıldız 14.04.2018 11:17

У него нет способа получить количество потоков? Просто интересно, почему?

djangofan 16.10.2018 20:34

Этот работал у меня как на Windows 10, так и на macOS High Sierra.

gbmhunter 14.11.2018 19:01

Это работает, если вы используете Oracle JVM. Если вы контролируете, какая версия Java установлена, это отличное решение. Однако он не будет работать с Open JDK, на который переходят все больше и больше пользователей, поскольку Oracle изменила лицензионные требования на JDK11.

Daniel Widdis 16.05.2019 05:13

Это правильный ответ, начиная с Java 9. Цикл по свойствам java.lang OperatingSystemMXBean вместо com.sun теперь выдает исключение.

Thor Lancaster 26.07.2019 20:12

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

Be careful when using Sigar, there are problems on x64 machines... Sigar 1.6.4 is crashing: EXCEPTION_ACCESS_VIOLATION and it seems the library doesn't get updated since 2010

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

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

Другие вопросы по теме