Получить системную информацию на уровне ОС
В настоящее время я создаю Java-приложение, которое может работать на разных платформах, но, прежде всего, в версиях Solaris, Linux и Windows.
Кто-нибудь был в состоянии успешно извлечь информацию, такую как текущее используемое дисковое пространство, загрузка ЦП и память, используемая в основной ОС? Как насчет того, что потребляет само приложение Java?
Желательно, чтобы я получил эту информацию без использования JNI.
17 ответов
Вы можете получить ограниченную информацию о памяти из класса 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());
}
}
}
Пакет 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();
}
}
}
Я думаю, что лучший способ - реализовать API SIGAR от Hyperic. Он работает для большинства основных операционных систем (чертовски близко ко всему современному) и с ним очень легко работать. Разработчики очень быстро реагируют на свои форумы и списки рассылки. Мне также нравится, что это лицензия GPL2 Apache. Они также предоставляют множество примеров на Java!
SIGAR == Инструмент системной информации, сбора и отчетности.
Есть проект Java, который использует JNA (поэтому нет собственных библиотек для установки) и находится в активной разработке. В настоящее время он поддерживает Linux, OSX, Windows, Solaris и FreeBSD и предоставляет информацию об оперативной памяти, процессоре, батарее и файловой системе.
Для окон я пошел по этому пути.
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();
Вот ссылка с деталями.
Вы можете получить некоторую информацию системного уровня, используя System.getenv()
, передавая имя соответствующей переменной среды в качестве параметра. Например, в Windows:
System.getenv("PROCESSOR_IDENTIFIER")
System.getenv("PROCESSOR_ARCHITECTURE")
System.getenv("PROCESSOR_ARCHITEW6432")
System.getenv("NUMBER_OF_PROCESSORS")
Для других операционных систем наличие / отсутствие и имена соответствующих переменных среды будут отличаться.
Добавьте зависимость 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));
}
Обычно, чтобы получить информацию об ОС низкого уровня, вы можете вызывать специфические для ОС команды, которые предоставляют вам необходимую информацию с помощью Runtime.exec() или читать файлы, такие как /proc/* в Linux.
Посмотрите на API, доступные в пакете java.lang.management. Например:
OperatingSystemMXBean.getSystemLoadAverage()
ThreadMXBean.getCurrentThreadCpuTime()
ThreadMXBean.getCurrentThreadUserTime()
Там также есть множество других полезных вещей.
Использование ЦП не является простым - java.lang.management через com.sun.management.OperatingSystemMXBean.getProcessCpuTime подходит близко (см. Превосходный фрагмент кода Патрика выше), но обратите внимание, что он дает только доступ ко времени, потраченному ЦП в вашем процессе. он не скажет вам о времени процессора, потраченном на другие процессы, или даже о времени процессора, потраченном на выполнение системных операций, связанных с вашим процессом.
например, у меня есть интенсивный по сети процесс Java - он работает единственно, а загрузка процессора составляет 99%, но только 55% из них указывается как "процессор процессора".
даже не заводите меня на "среднюю нагрузку", так как она почти бесполезна, несмотря на то, что это единственный элемент, связанный с процессором, в компоненте MX. лишь бы солнце в их редкой мудрости выставляло что-то вроде "getTotalCpuTime"...
для серьезного мониторинга процессора SIGAR, упомянутый Мэттом, кажется лучшим выбором.
На 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();
}
}
Если вы используете виртуальную машину Jrockit, то вот другой способ получить использование процессора виртуальной машины. Компонент времени выполнения также может дать вам нагрузку на процессор на процессор. Я использовал это только в 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");
Он все еще находится в стадии разработки, но вы уже можете использовать 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());
//[...]
Один простой способ, который можно использовать для получения информации об уровне ОС, и я протестировал его на моем Mac, который хорошо работает:
OperatingSystemMXBean osBean =
(OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
return osBean.getProcessCpuLoad();
Вы можете найти много соответствующих метрик операционной системы здесь
Чтобы получить в Java-коде среднюю загрузку системы в 1 минуту, 5 минут и 15 минут, вы можете сделать это, выполнив команду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);
Эй, вы можете сделать это с интеграцией Java/ Com. Получая доступ к функциям WMI, вы можете получить всю информацию.
Не совсем то, что вы просили, но я бы рекомендовал проверить ArchUtils и SystemUtils отcommons-lang3
. Они также содержат некоторые соответствующие вспомогательные средства, например :
import static org.apache.commons.lang3.ArchUtils.*;
import static org.apache.commons.lang3.SystemUtils.*;
System.out.printf("OS architecture: %s\n", OS_ARCH); // OS architecture: amd64
System.out.printf("OS name: %s\n", OS_NAME); // OS name: Linux
System.out.printf("OS version: %s\n", OS_VERSION); // OS version: 5.18.16-200.fc36.x86_64
System.out.printf("Is Linux? - %b\n", IS_OS_LINUX); // Is Linux? - true
System.out.printf("Is Mac? - %b\n", IS_OS_MAC); // Is Mac? - false
System.out.printf("Is Windows? - %b\n", IS_OS_WINDOWS); // Is Windows? - false
System.out.printf("JVM name: %s\n", JAVA_VM_NAME); // JVM name: Java HotSpot(TM) 64-Bit Server VM
System.out.printf("JVM vendor: %s\n", JAVA_VM_VENDOR); // JVM vendor: Oracle Corporation
System.out.printf("JVM version: %s\n", JAVA_VM_VERSION); // JVM version: 11.0.12+8-LTS-237
System.out.printf("Username: %s\n", getUserName()); // Username: johndoe
System.out.printf("Hostname: %s\n", getHostName()); // Hostname: garage-pc
var processor = getProcessor();
System.out.printf("CPU arch: %s\n", processor.getArch()) // CPU arch: BIT_64
System.out.printf("CPU type: %s\n", processor.getType()); // CPU type: X86