问题
I've been investigating the best approach to achieve the following data for a specific process:
- CPU usage
- Memory usage
- Disk usage
- Network usage
I decided to go with OSHI (Operating system & hardware information) API. Unfortunate for me , this API isn't giving me the desired info out of the box, it requires some basic knowledge of how to calculate , for example the cpu usage per process.
My Question is: How can I get the memory, disk, network usage by process id ?
using the following example of cpu usage data per prcoess
For example:
To get the actual CPU usage of a claculator.exe running process:
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.software.os.OSProcess;
import oshi.software.os.OperatingSystem;
public class processCPUusage {
public static void main(String[] args) throws InterruptedException {
OSProcess process;
long currentTime,previousTime = 0,timeDifference;
double cpu;
int pid = 7132;
SystemInfo si = new SystemInfo();
OperatingSystem os = si.getOperatingSystem();
CentralProcessor processor = si.getHardware().getProcessor();
int cpuNumber = processor.getLogicalProcessorCount();
boolean processExists = true;
while (processExists) {
process = os.getProcess(pid); // calculator.exe process id
if (process != null) {
// CPU
currentTime = process.getKernelTime() + process.getUserTime();
if (previousTime != -1) {
// If we have both a previous and a current time
// we can calculate the CPU usage
timeDifference = currentTime - previousTime;
cpu = (100d * (timeDifference / ((double) 1000))) / cpuNumber;
System.out.println(cpu);
}
previousTime = currentTime;
Thread.sleep(1000);
} else {
processExists = false;
}
}
}
}
The framework I'm using https://github.com/oshi/oshi/tree/master/src/site/markdown demonstrates the desired functionality but lacks proper examples
- Language: Java 8
- Build tool: Maven 2
- OS: Windows 10*
OSHI library + slf4j
<dependency>
<groupId>com.github.dblock</groupId>
<artifactId>oshi-core</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
回答1:
Main Method
public static void main(String[] args) {
int pid=8924;
for (int i = 0; i < 10; i++) {
diskUtilizationPerProcess(pid);
memoryUtilizationPerProcess(pid);
cpuUtilizationPerProcess(pid);
Util.sleep(5000);
}
}
Disk/IO :
public static void diskUtilizationPerProcess(int pid) {
/**
* ByteRead : Returns the number of bytes the process has read from disk.
* ByteWritten : Returns the number of bytes the process has written to disk.
*/
OSProcess process;
SystemInfo si = new SystemInfo();
OperatingSystem os = si.getOperatingSystem();
process = os.getProcess(pid);
System.out.println("\nDisk I/O Usage :");
System.out.println("I/O Reads: "+process.getBytesRead());
System.out.println("I/O Writes: "+process.getBytesWritten());
}
Cpu Usage :
public static void cpuUtilizationPerProcess(int processId) {
/**
* User Time : Returns the number of milliseconds the process has executed in user mode.
* Kernel Time : Returns the number of milliseconds the process has executed in kernel/system mode.
*/
SystemInfo systemInfo = new SystemInfo();
CentralProcessor processor = systemInfo.getHardware().getProcessor();
int cpuNumber = processor.getLogicalProcessorCount();
//int processId = systemInfo.getOperatingSystem().getProcessId();
OSProcess process = systemInfo.getOperatingSystem().getProcess(processId);
long currentTime = process.getKernelTime() + process.getUserTime();
long timeDifference = currentTime - previousTime;
double processCpu = (100 * (timeDifference / 5000d)) / cpuNumber;
previousTime = currentTime;
System.out.println("\nCPU Usage :");
System.out.println("CPU : "+(int)processCpu+"%");
}
Memory Usage
public static void memoryUtilizationPerProcess(int pid) {
/**
* Resident Size : how much memory is allocated to that process and is in RAM
*/
OSProcess process;
SystemInfo si = new SystemInfo();
OperatingSystem os = si.getOperatingSystem();
process = os.getProcess(pid);
System.out.println("\nMemory Usage :");
System.out.println("Resident Size: "+process.getResidentSetSize());
}
回答2:
The original answer in 2017 below is now out of date. The OSProcess
class now has many more methods that mostly answer the original request.
The answer by Shikari is good for manual calculations. I'll also note the presence of a method getProcessCpuLoadBetweenTicks()
on the OSProcess
object starting in version 5.x that will do the CPU calculation for you.
Previous answer below:
I am the one who implemented the OSProcess class in OSHI that you are referencing, and have been communicating with you in an Issue on that project.
While OSHI does not currently provide all the functionality in the OSProcess
interface, it does provide you access methods to the WMI classes which will provide you all the information you seek. If you take a look at the WindowsOperatingSystem class which implements the getProcess()
method you're using, you can copy/modify the code using WMIUtil
to directly fetch the bits of information that you need.
OSHI currently fetches from the Win32_Process WMI class but as I've mentioned on the issue, it might be better to get information instead from Win32_PerfRawData_PerfProc_Process (which provides the raw data you can use for direct calculations) or Win32_PerfFormattedData_PerfProc_Process. In these classes you can find:
CPU usage
- ElapsedTime
- PercentPrivilegedTime
- PercentProcessorTime
- PercentUserTime
(Note while the name says "Percent" the raw data actually includes incrementing "ticks")
Memory usage
- VirtualBytes
- WorkingSet
Disk usage, Network usage
- IOReadBytesPerSec;
- IOWriteBytesPerSec;
In these classes, both Disk and Network are combined in the totals. (Again, for the "raw data" ignore the "per sec" part, it will give increasing total amounts of data).
I do not think Windows keeps track of the difference in Disk vs. Network IO on a per-process basis.
Steps you should take:
Define a comma-separated string with the WMI field names you want
Define a
ValueType
array with types matching the field names, in the same orderExecute
Map<String, List<Object>> procs = WmiUtil.selectObjectsFrom(null, "Win32_PerfRawData_PerfProc_Process", processProperties, String.format("WHERE IdProcess=%d", pid), processPropertyTypes);
Fetch each value you want using
procs.get("FieldNameHere").get(0)
来源:https://stackoverflow.com/questions/44474799/java-windows-by-process-id-get-memory-usage-disk-usage-network-usage