通过oshi这个三方库来获取,目前这个最准确。
引入依赖
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>3.5.0</version>
</dependency>
Demo代码
import oshi.SystemInfo;
import oshi.software.os.OSProcess;
import oshi.software.os.OperatingSystem;
import oshi.util.FormatUtil;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
public class Test {
public static void main(String[] args) {
ExecutorService service = Executors.newSingleThreadScheduledExecutor();
final long[] bytesWritten = {0};
final long[] bytesRead = {0};
service.execute(new Runnable() {
@SneakyThrows
@Override
public void run() {
while(true) {
SystemInfo systemInfo = new SystemInfo();
OperatingSystem os = systemInfo.getOperatingSystem();
int processId = os.getProcessId();
OSProcess process = os.getProcess(processId);
long curBytesWritten = process.getBytesWritten();
long curBytesRead = process.getBytesRead();
if (bytesWritten[0] == 0 ){
bytesWritten[0] = curBytesWritten;
}
if (bytesRead[0] == 0 ){
bytesRead[0] = curBytesRead;
}
log.info("pid %d 当前进程:占用内存 %s | 占用CPU(%%) %.2f | 写入(bytes) %d | 读取(bytes) %d".formatted(processId, FormatUtil.formatBytes(process.getResidentSetSize()), getProcessCpuLoad(),
curBytesWritten - bytesWritten[0],
curBytesRead - bytesRead[0]));
bytesWritten[0] = curBytesWritten;
bytesRead[0] = curBytesRead;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
log.error("性能监控时出现异常:{}",e);
}
}
}
});
}
/**
* 获取当前进程的CPU利用率
* @return
* @throws Exception
*/
public static double getProcessCpuLoad() throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
AttributeList list = mbs.getAttributes(name, new String[]{ "ProcessCpuLoad" });
if (list.isEmpty()) {
return Double.NaN;
}
Attribute att = (Attribute)list.get(0);
Double value = (Double)att.getValue();
// usually takes a couple of seconds before we get real values
if (value == -1.0) {
return Double.NaN;
}
// returns a percentage value with 1 decimal point precision
return ((int)(value * 1000) / 10.0);
}
}
效果图
如果还想对这些数据进行统计的话,我这里也写了个小DEMO,用于解析日志文件,然后计算出下面这些指标:
平均RAM使用(MB)548.36 | 总CPU利用率(%) 12.70 | 平均写入速率(kb/s) 713 | 平均读取速率(kb/s) 346
最大RAM使用(MB)838.40 | 最大CPU利用率(%) 25.20 | 最大写入速率(kb/s) 8161 | 最大读取速率(kb/s) 65582
需要注意,执行代码前要修改日志所在路径folderPath ,以及日志持续时间durationSeconds
DEMO代码
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test {
public static void main(String[] args) {
// 定义指定文件夹路径
String folderPath = "D:\\xx\\logs\\Info\\日志";
File folder = new File(folderPath);
// 遍历文件夹下所有文件
int countFile = 1;
//持续时间
double durationSeconds = 2271;
double totalRAMUseage = 0d;
double maxRAMUseage = 0d;
double totalCPUUseage = 0d;
double maxCPUUseage = 0d;
long maxReadBytes = 0;
long totalReadBytes = 0;
long maxWrittenBytes = 0;
long totalWrittenBytes = 0;
File[] files = folder.listFiles((d, name) -> name.endsWith(".info"));
// 使用自定义的Comparator按照创建时间从早到晚排序
Arrays.sort(files, Comparator.comparingLong(File::lastModified));
for (File file: files) {
if (file.isFile() && file.getName().endsWith(".info")) {
// 打开文件并按行读取
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
System.out.println("正在解析日志%s(%d/%d)".formatted(file.getName(),countFile++,folder.listFiles().length));
String line;
while ((line = br.readLine()) != null) {
if (line.contains("占用内存")) {
double ramUsage = getRAMUsageAfterSpecifiedString(line);
double cpuUsage = getCPUUsageAfterSpecifiedString(line);
long readBytes = getReadBytesAfterSpecifiedString(line);
long writtenBytes = getWrittenBytesAfterSpecifiedString(line);
if (ramUsage > maxRAMUseage){
System.out.println("max ram "+line);
}
if (cpuUsage > maxCPUUseage){
System.out.println("max cpu "+line);
}
if (readBytes > maxReadBytes){
System.out.println("max read "+line);
}
if (writtenBytes > maxWrittenBytes){
System.out.println("max write "+line);
}
maxRAMUseage = (ramUsage > maxRAMUseage ? ramUsage : maxRAMUseage);
maxCPUUseage = (cpuUsage > maxCPUUseage ? cpuUsage : maxCPUUseage);
maxReadBytes = (readBytes > maxReadBytes ? readBytes : maxReadBytes);
maxWrittenBytes = (writtenBytes > maxWrittenBytes ? writtenBytes : maxWrittenBytes);
totalRAMUseage += ramUsage;
totalCPUUseage += cpuUsage;
totalReadBytes += readBytes;
totalWrittenBytes += writtenBytes;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("平均RAM使用(MB)%.2f | 总CPU利用率(%%) %.2f | 平均写入速率(kb/s) %d | 平均读取速率(kb/s) %d ".formatted(
totalRAMUseage / durationSeconds,
totalCPUUseage/ durationSeconds,
totalWrittenBytes / (long)durationSeconds/1024,
totalReadBytes/(long)durationSeconds/1024)
);
System.out.println("最大RAM使用(MB)%.2f | 最大CPU利用率(%%) %.2f | 最大写入速率(kb/s) %d | 最大读取速率(kb/s) %d ".formatted(
maxRAMUseage,
maxCPUUseage,
maxWrittenBytes/1024,
maxReadBytes/1024
));
}
public static double getRAMUsageAfterSpecifiedString(String specifiedString){
// 定义待匹配的字符串
// 定义正则表达式
String patternString = ".*占用内存 (\\d+\\.\\d+) GiB.*";
Pattern pattern = Pattern.compile(patternString);
// 进行匹配
Matcher matcher = pattern.matcher(specifiedString);
if (matcher.matches()) {
// 获取第一组匹配到的数字
String numberStr = matcher.group(1);
return Double.parseDouble(numberStr)*1024;
}else {
patternString = ".*占用内存 (\\d+\\.\\d+) MiB.*";
pattern = Pattern.compile(patternString);
// 进行匹配
matcher = pattern.matcher(specifiedString);
if (matcher.matches()) {
// 获取第一组匹配到的数字
String numberStr = matcher.group(1);
return Double.parseDouble(numberStr);
}
}
return 0d;
}
public static double getCPUUsageAfterSpecifiedString(String specifiedString){
// 定义待匹配的字符串
// 定义正则表达式
String patternString = ".*占用CPU\\(%\\) (\\d+\\.\\d+).*";
Pattern pattern = Pattern.compile(patternString);
// 进行匹配
Matcher matcher = pattern.matcher(specifiedString);
if (matcher.matches()) {
// 获取第一组匹配到的数字
String numberStr = matcher.group(1);
return Double.parseDouble(numberStr);
}
return 0d;
}
public static long getReadBytesAfterSpecifiedString(String specifiedString){
// 定义待匹配的字符串
// 定义正则表达式
String patternString = ".*读取\\(bytes\\) (\\d+).*";
Pattern pattern = Pattern.compile(patternString);
// 进行匹配
Matcher matcher = pattern.matcher(specifiedString);
if (matcher.matches()) {
// 获取第一组匹配到的数字
String numberStr = matcher.group(1);
return Long.parseLong(numberStr);
}
return 0;
}
public static long getWrittenBytesAfterSpecifiedString(String specifiedString){
// 定义待匹配的字符串
// 定义正则表达式
String patternString = ".*写入\\(bytes\\) (\\d+).*";
Pattern pattern = Pattern.compile(patternString);
// 进行匹配
Matcher matcher = pattern.matcher(specifiedString);
if (matcher.matches()) {
// 获取第一组匹配到的数字
String numberStr = matcher.group(1);
return Long.parseLong(numberStr);
}
return 0;
}
}