Получить системную информацию на уровне ОС

232

В настоящее время я создаю Java-приложение, которое может работать на разных платформах, но в первую очередь это варианты Solaris, Linux и Windows.

Кто-нибудь был в состоянии успешно извлечь информацию, такую ​​как текущее используемое дисковое пространство, загрузка ЦП и память, используемая в основной ОС? Как насчет того, что потребляет само приложение Java?

Желательно, чтобы я получил эту информацию без использования JNI.

Стив М
источник
3
Что касается свободной памяти, см. Stackoverflow.com/a/18366283/231397 ( Runtime.getRuntime().freeMemory()как указано в принятом ответе, НЕ дает вам объем свободной памяти.
Кристиан Фрис,

Ответы:

206

Вы можете получить ограниченную информацию о памяти из класса Runtime. Это действительно не совсем то, что вы ищете, но я подумал, что предоставлю это ради полноты. Вот небольшой пример. Редактировать: Вы также можете получить информацию об использовании диска из класса java.io.File. Для использования дискового пространства требуется Java 1.6 или выше.

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
Я думаю, что «Общая память, используемая в настоящее время JVM» немного сбивает с толку. В Javadoc говорится, что функция возвращает «общий объем памяти, доступный в настоящее время для текущих и будущих объектов, измеренный в байтах». Звучит больше как память, оставшаяся и не используемая.
Дирк
@Dirk: я обновил формулировку в соответствии с вашим комментарием. Спасибо!
Уильям Брендель
@LeonardoGaldioli: я не знаю характеристик производительности этих классов и методов, но я не удивлюсь, если они не будут оптимизированы для скорости. Другие ответы объясняют, как собирать определенную информацию с помощью JMX, что может быть быстрее.
Уильям Брендель
15
Это не отвечает на вопрос правильно. Все эти данные передаются в JVM, а не в ОС ...
Alvaro
Я знаю, что эта тема довольно устарела. НО: если вам действительно нужно количество ядер ЦП, не используйте это решение. У меня двухъядерный процессор с двумя потоками для каждого ядра. JVM возвращает не аппаратные ядра, а программные ядра / потоки.
F_Schmidt
95

Пакет java.lang.management дает вам гораздо больше информации, чем среда выполнения - например, он даст вам кучную память ( ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()) отдельно от не кучевой памяти ( ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage()).

Вы также можете получить нагрузку на процессор (без написания собственного кода JNI), но вам необходимо привести java.lang.management.OperatingSystemMXBeanк com.sun.management.OperatingSystemMXBean. Это работает на Windows и Linux, я не проверял это в другом месте.

Например ... вызывайте метод get getCpuUsage () чаще, чтобы получить более точные показания.

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
Чтобы получить его для компиляции, замените приведение OperatingSystemMXBeanна com.sun.management.OperatingSystemMXBeanи предварите все экземпляры getOperatingSystemMXBean()с ManagementFactory.. Вы должны импортировать все классы соответствующим образом.
tmarthal
2
Я получаю использование процессора как 0 для всего. я изменил формулу использования процессора на cpuUsage = processCpuTime / systemTime. Я получаю значение для использования процессора, которое я не понимаю.
Радж
делает 1.0 в качестве результата от getCpuUsageсреднего , что система использует все свои availableProcessors на 100%?
user454322
2
Я всегда получаю 0, как сказал @Raj ... не могли бы вы привести пример, как использовать этот код?
dm76
1
Попробуйте((double)( processCpuTime - lastProcessCpuTime )) / ((double)( systemTime - lastSystemTime ))
Энтони О.
43

Я думаю, что лучший способ - реализовать API SIGAR от Hyperic . Он работает для большинства основных операционных систем (чертовски близко ко всему современному) и с ним очень легко работать. Разработчики очень быстро реагируют на свои форумы и списки рассылки. Мне также нравится, что это лицензия GPL2 Apache . Они также предоставляют множество примеров на Java!

SIGAR == Инструмент системной информации, сбора и отчетности.

Мэтт Каммингс
источник
2
@ Йохан - Не ленись! Вы можете узнать это, прочитав связанную веб-страницу. (И это зависит от того, что вы подразумеваете под «независимостью от платформы».)
Стивен С.
2
@StephenC: Sigar использует файлы .dll, что делает его зависимым от платформы. API более высокого уровня может быть в Java, это другая история
Лимонный сок
1
@Artificial_Intelligence да, но он предоставляет библиотеки (написанные на с) для большинства популярных платформ. Он не более зависим от платформы, чем сам jvm. Java API более высокого уровня должен быть совместимым на всех платформах.
Иешурун
8
Sigar не обновляется с 2010 года и, похоже, имеет ошибку в 64-битных системах: stackoverflow.com/questions/23405832/…
Alvaro
1
И SIGAR также делает сбой JVM (хотя и с перерывами), но я уверен, что вы не возьмете этот риск в производство.
AKS
25

Есть Java-проект, который использует JNA (поэтому нет собственных библиотек для установки) и находится в активной разработке. В настоящее время он поддерживает Linux, OSX, Windows, Solaris и FreeBSD и предоставляет информацию об оперативной памяти, процессоре, батарее и файловой системе.

дБ.
источник
Нет родных библиотек, возможно, вводит в заблуждение. В проекте используются нативные библиотеки, даже если они еще не написаны, и вам, очевидно, не нужно их устанавливать.
Стивен C
1
Ты прав. JNA использует libffi, который имеет нативные компоненты. Но для всех целей, похоже, нет нативных библиотек (определенно нет для установки).
дБ.
@StephenC, хотя то, что вы говорите, верно, оно вводит в заблуждение, потому что то же самое для rt.jar, который также вызывает нативные методы. единственная причина, по которой люди заботятся о нативных методах, заключается в том, что им приходится компилировать и / или устанавливать их, что часто является нетривиальной задачей. Поскольку libffi широко используется, перенесен и установлен, это уменьшает трудности. так что технически вы правы, но практически это не имеет значения.
ОДП
@rbp - есть еще одна причина, по которой люди, которые опытные Java-разработчики предпочитают избегать нативных библиотек Собственная библиотека с ошибками (включая проблемы безопасности потоков или проблемы с управлением памятью) может дестабилизировать JVM хоста. Это не проблема "это не имеет значения" ....
Стивен C
@StephenC делает мой сервер достаточно опытным ?
ОДП
13

Для окон я пошел по этому пути.

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

Вот ссылка с деталями.

Ян Хонски
источник
11

Вы можете получить некоторую информацию системного уровня System.getenv(), передав в качестве параметра имя соответствующей переменной среды. Например, в Windows:

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

Для других операционных систем наличие / отсутствие и имена соответствующих переменных среды будут отличаться.

Александр
источник
1
Они зависят от платформы, потому что имена переменных различаются в разных системах. Об этом говорится в статье Oracle о переменных среды. Я также нахожу способ получить независимый от системы способ.
Лимонный сок
Под Linux (Ubuntu 17.10) не так много интересной информации о процессорах в среде.
pveentjer
8

Добавьте OSHI-зависимость через maven:

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

Получите оставшуюся емкость батареи в процентах:

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 имеет большую часть информации, описанной в других комментариях. Он использует JNA, чтобы по возможности получать через нативные вызовы ОС.
Даниэль Виддис
6

Посмотрите на API, доступные в пакете java.lang.management . Например:

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

Там также есть множество других полезных вещей.

Стаффан
источник
2
OperatingSystemMXBean.getSystemLoadAverage () не реализован в Windows, потому что «это слишком дорого»
MikeNereson
1
ThreadMXBean.getCurrentThreadCpuTime () возвращает только продолжительность работы этого потока. Не процент использования процессора.
MikeNereson
5

Обычно, чтобы получить информацию об ОС низкого уровня, вы можете вызывать специальные команды ОС, которые предоставляют вам необходимую информацию с помощью Runtime.exec () или читать файлы, такие как / proc / * в Linux.

Питер Лори
источник
5

Использование ЦП не является простым - java.lang.management через com.sun.management.OperatingSystemMXBean.getProcessCpuTime подходит близко (см. Превосходный фрагмент кода Патрика выше), но обратите внимание, что он дает только доступ ко времени, потраченному ЦП в вашем процессе. он не скажет вам о времени процессора, потраченном на другие процессы, или даже о времени процессора, потраченном на выполнение системных операций, связанных с вашим процессом.

например, у меня есть интенсивный по сети процесс Java - он работает только и процессор на 99%, но только 55% из них сообщается как «процессор процессора».

даже не заводите меня на «среднюю нагрузку», поскольку она почти бесполезна, несмотря на то, что это единственный элемент, связанный с процессором, в компоненте MX. лишь бы солнце в их редкой мудрости выставляло что-то вроде "getTotalCpuTime" ...

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

Переменная облачность
источник
4

На Windows, вы можете запустить systeminfoкоманду и возвращает свой выход, например , с помощью следующего кода:

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
источник
3

Если вы используете Jrockit VM, то здесь есть другой способ получить загрузку ЦП виртуальной машины. Компонент времени выполнения также может дать вам нагрузку на процессор на процессор. Я использовал это только в Red Hat Linux для наблюдения за производительностью Tomcat. Вы должны включить JMX remote в 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

Он все еще находится в стадии разработки, но вы уже можете использовать jHardware

Это простая библиотека, которая удаляет системные данные, используя Java. Работает как в Linux, так и в 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
источник
Хорошо, но он использует версии Guava и JNA, которые конфликтуют с моими потребностями (например, см. GLASSFISH-21367 ).
lu_ko
Здравствуйте, JNA была представлена ​​в версии 0.8 jHardware. Используется только для данных о температуре и датчиках. Если вам не нужна эта информация, вы можете использовать версию 0.7. То же самое для гуавы. В этом случае вам придется использовать версию 0.6.3.
profesor_falken
2

Один простой способ, который можно использовать для получения информации об уровне ОС, и я протестировал на моем Mac, который хорошо работает:

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

Вы можете найти много соответствующих метрик операционной системы здесь

Амандип Сингх
источник
1

Эй, вы можете сделать это с интеграцией Java / Com. Получая доступ к функциям WMI, вы можете получить всю информацию.


источник
0

Чтобы получить среднее значение загрузки системы, равное 1 минуте, 5 минутам и 15 минутам внутри Java-кода, вы можете сделать это, выполнив команду, cat /proc/loadavgиспользуя и интерпретируя ее, как показано ниже:

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

И получить физическую системную память , выполнив команду free -mи затем интерпретировав ее, как показано ниже:

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);
Кришна Прасад
источник