如何在独立Java应用中监控Minecraft服务器(另一JVM)的资源
监控外部Minecraft服务器JVM的CPU与内存使用率(基于MXBeans)
前置准备
- 确保项目类路径包含JDK自带的
tools.jar(位于JDK安装目录的lib文件夹下),因为要用到JVM Attach API。 - 先获取Minecraft服务器的进程PID:Windows用
tasklist命令,Linux/macOS用jps命令,找到对应Java进程的ID。
核心实现代码
1. 连接到目标JVM
通过Attach API建立与Minecraft服务器JVM的连接,这是获取远程MXBeans的基础:
import com.sun.tools.attach.AttachNotSupportedException; import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.VirtualMachineDescriptor; import java.io.IOException; import java.util.List; // 根据进程名称匹配获取目标PID(比如Minecraft服务器进程名通常包含minecraft_server.jar) private static String getTargetPid(String processKeyword) { List<VirtualMachineDescriptor> runningVms = VirtualMachine.list(); for (VirtualMachineDescriptor vmd : runningVms) { if (vmd.displayName().contains(processKeyword)) { return vmd.id(); } } return null; } // 连接到目标JVM private static VirtualMachine connectToTarget(String pid) throws IOException, AttachNotSupportedException { return VirtualMachine.attach(pid); }
2. 内存使用率监控与进度条更新
利用MemoryMXBean获取堆内存使用情况,计算使用率后更新JProgressBar:
import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.MemoryUsage; import javax.swing.JProgressBar; // 更新内存监控进度条 public static void refreshMemoryStatus(VirtualMachine targetVm, JProgressBar memoryBar) throws Exception { // 获取远程JVM的MemoryMXBean代理 MemoryMXBean memoryBean = ManagementFactory.newPlatformMXBeanProxy( targetVm.getConnectorAddress(), MemoryMXBean.class.getName(), true ); MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage(); long used = heapUsage.getUsed(); long max = heapUsage.getMax(); int usagePercent = (int) ((used * 100) / max); // Swing组件必须在EDT线程更新 javax.swing.SwingUtilities.invokeLater(() -> { memoryBar.setValue(usagePercent); memoryBar.setString(String.format("内存: %d%%", usagePercent)); memoryBar.setStringPainted(true); }); }
3. CPU使用率监控与进度条更新
通过OperatingSystemMXBean获取目标进程的CPU负载,转换为百分比后更新进度条:
import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; import javax.swing.JProgressBar; // 更新CPU监控进度条 public static void refreshCpuStatus(VirtualMachine targetVm, JProgressBar cpuBar) throws Exception { OperatingSystemMXBean osBean = ManagementFactory.newPlatformMXBeanProxy( targetVm.getConnectorAddress(), OperatingSystemMXBean.class.getName(), true ); // getProcessCpuLoad返回0.0-1.0的数值,转为百分比 double cpuLoad = osBean.getProcessCpuLoad(); int usagePercent = (int) (cpuLoad * 100); // 处理初始未收集到数据时的-1值 usagePercent = Math.max(usagePercent, 0); javax.swing.SwingUtilities.invokeLater(() -> { cpuBar.setValue(usagePercent); cpuBar.setString(String.format("CPU: %d%%", usagePercent)); cpuBar.setStringPainted(true); }); }
4. 定时刷新监控数据
用Swing Timer实现每秒自动刷新监控数据:
import javax.swing.Timer; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; // 启动定时监控任务 public static void startMonitoring(String targetPid, JProgressBar cpuBar, JProgressBar memoryBar) { try { VirtualMachine targetVm = connectToTarget(targetPid); // 每1000毫秒(1秒)刷新一次 Timer timer = new Timer(1000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { refreshCpuStatus(targetVm, cpuBar); refreshMemoryStatus(targetVm, memoryBar); } catch (Exception ex) { ex.printStackTrace(); // 目标JVM断开连接时停止定时器 ((Timer) e.getSource()).stop(); } } }); timer.start(); } catch (Exception ex) { ex.printStackTrace(); } }
5. 整合到你的GUI中
假设你已有包含两个JProgressBar的窗口,在初始化时启动监控:
import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JProgressBar; import java.awt.GridLayout; public class McServerMonitor extends JFrame { private JProgressBar cpuBar; private JProgressBar memoryBar; public McServerMonitor() { setTitle("Minecraft服务器监控"); setSize(400, 150); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); JPanel panel = new JPanel(new GridLayout(2, 1)); cpuBar = new JProgressBar(); memoryBar = new JProgressBar(); panel.add(cpuBar); panel.add(memoryBar); add(panel); // 替换为你的Minecraft服务器进程关键词或直接写PID String targetPid = getTargetPid("minecraft_server.jar"); if (targetPid != null) { startMonitoring(targetPid, cpuBar, memoryBar); } else { System.out.println("未找到目标Minecraft服务器进程"); } } public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(() -> { new McServerMonitor().setVisible(true); }); } // 把前面的getTargetPid、connectToTarget、refreshMemoryStatus、refreshCpuStatus、startMonitoring方法复制到这里 }
关键注意事项
- 权限要求:运行监控程序的用户需与Minecraft服务器进程拥有相同权限,否则Attach API无法建立连接。
- tools.jar依赖:如果用Maven,需手动将
tools.jar添加到项目依赖;普通项目直接将其加入类路径即可。 - 版本兼容:尽量保证监控程序与Minecraft服务器的JDK版本一致,避免API兼容性问题。
- 异常处理:实际使用中可添加进程断开后的重连逻辑,提升稳定性。
内容的提问来源于stack exchange,提问作者Mute
相关产品推荐
相关产品推荐

