使用jmx监控java垃圾回收,核心是获取 mbeanserverconnection 并查询 java.lang:type=garbagecollector,name=* 和 java.lang:type=memorypool,name=* 的mbean。通过轮询这些mbean的属性(如 collectioncount、collectiontime、usage),可以实时获取gc次数、耗时及内存池使用情况。若需远程监控,需确保目标jvm启动时开启了jmx端口并配置了认证,本地监控则可直接通过 mbeanserverlocator 或 managementfactory 获取连接。

如何获取本地JVM的GC MBean连接
在本地进程中,直接通过 ManagementFactory.getPlatformMBeanServer() 即可获取 MBeanServer 实例,无需网络通信。接着使用 MBeanServerConnection.queryNames() 配合 ObjectName 模式匹配,筛选出所有垃圾回收器MBean。这种方式延迟最低,适合进程内监控工具或Agent的实现。

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.util.Set;
public class LocalGCMonitor {
public static void main(String[] args) throws Exception {
// 1. 获取本地MBean服务器
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
// 2. 定义GC MBean的名称模式
ObjectName gcPattern = new ObjectName("java.lang:type=GarbageCollector,name=*");
// 3. 查询所有GC MBean
Set<ObjectName> gcNames = mbs.queryNames(gcPattern, null);
for (ObjectName name : gcNames) {
// 4. 读取关键属性:收集次数和总耗时
Long collectionCount = (Long) mbs.getAttribute(name, "CollectionCount");
Long collectionTime = (Long) mbs.getAttribute(name, "CollectionTime");
String gcName = name.getKeyProperty("name");
System.out.println("GC: " + gcName + ", Count: " + collectionCount + ", Time(ms): " + collectionTime);
}
}
}运行上述代码,输出将显示当前JVM中每个垃圾回收器的名称、累计收集次数以及累计消耗的毫秒数。例如,如果使用G1 GC,可能会看到 G1 Young Generation 和 G1 Old Generation 两个MBean。这些数据是累积值,需要自行计算差值以获得瞬时速率。
立即学习“Java免费学习笔记(深入)”;
如何远程监控JVM的内存池状态
远程监控需要目标JVM在启动时添加JMX参数,如 -Dcom.sun.management.jmxremote。客户端通过 JMXConnectorFactory.connect() 建立连接后,除了查询GC MBean,还需重点监控内存池(MemoryPool)MBean。内存池MBean提供了 Usage 属性,反映堆内不同区域(如Eden、Survivor、Old Gen)的当前内存使用量、最大容量和阈值。通过对比 Usage.used 和 Usage.max,可以判断内存是否接近上限,从而辅助GC调优。

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.util.HashMap;
import java.util.Map;
public class RemoteMemoryMonitor {
public static void main(String[] args) throws Exception {
// 1. 构建远程JMX URL (替换为实际IP和端口)
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9090/jmxrmi");
// 2. 建立连接 (无认证示例,生产环境需配置credentials)
Map<String, Object> env = new HashMap<>();
String[] creds = new String[]{"admin", "password"};
env.put(JMXConnector.CREDENTIALS, creds);
try (JMXConnector connector = JMXConnectorFactory.connect(url, env)) {
MBeanServerConnection mbsc = connector.getMBeanServerConnection();
// 3. 查询内存池MBean
ObjectName poolPattern = new ObjectName("java.lang:type=MemoryPool,name=*");
Set<ObjectName> poolNames = mbsc.queryNames(poolPattern, null);
for (ObjectName name : poolNames) {
// 4. 获取内存使用信息
Map usageMap = (Map) mbsc.getAttribute(name, "Usage");
long used = ((Number) usageMap.get("used")).longValue();
long max = ((Number) usageMap.get("max")).longValue();
String poolName = name.getKeyProperty("name");
System.out.printf("Pool: %s, Used: %d MB, Max: %d MB%n",
poolName, used / 1024 / 1024, max / 1024 / 1024);
}
}
}
}该程序连接到远程JVM后,会打印出每个内存池的已用内存和最大内存。注意,Usage 是一个 MemoryUsage 对象,在JMX中通常以Map形式返回或通过特定方法访问。在实际开发中,建议定期轮询并记录历史数据,以便绘制内存趋势图。若远程连接失败,请检查防火墙是否放行JMX端口,以及JVM启动参数是否正确配置了 jmxremote.port 和 jmxremote.authenticate。
当GC MBean的CollectionTime为0时意味着什么
当某个GC MBean的 CollectionTime 属性为0时,意味着自JVM启动以来,该垃圾回收器尚未执行过任何一次完整的垃圾收集。这通常发生在JVM刚启动不久,或者该特定的GC阶段(如G1的Young GC)还未被触发。如果预期应该发生GC但时间仍为0,可能表明堆内存充足,GC压力极小,或者监控的MBean名称与实际运行的GC器不匹配(例如在ZGC下某些旧版JDK可能没有对应的传统MBean)。此时应结合 CollectionCount 一起查看,若两者均为0,则确认未发生过GC。


















