ManagementFactory / MXBean 平台管理源码
概述
java.lang.management 是 JDK 提供的 JVM 管理与监控 API:通过一组 MXBean(Management eXtension Bean)接口暴露 JVM 的运行时信息——内存、线程、GC、类加载、操作系统与 JIT 编译状态。ManagementFactory 是获取这些 MXBean 的统一入口。
MXBean 采用标准化的 Open Type 映射:接口方法与属性经由 PlatformMBeanServer 暴露为 JMX 的 MBean 属性/操作,其底层数据几乎全部来自 sun.management.VMManagement 的 native 方法,最终走 JVM 内部的 JMM(Java Management eXtensions / Java Memory Management)接口。
本文基于 OpenJDK 21 源码,从 ManagementFactory 的工厂与 PlatformMBeanServer 的创建出发,逐层拆解 Runtime、Memory、Thread、GC、OS 各类 MXBean 的 native 调用链与数据模型。
核心源码解析
① ManagementFactory.getRuntimeMXBean() 的工厂
public static RuntimeMXBean getRuntimeMXBean() {
return ManagementFactoryHelper.getRuntimeMXBean();
}ManagementFactory 中每个 getXxxMXBean() 都是同类模式,其内部数据流:
ManagementFactory.getRuntimeMXBean()
→ ManagementFactoryHelper(sun.management 内部助手类)
→ 各 MXBean 实现类实例(RuntimeImpl / MemoryImpl / ThreadImpl ...)
→ 底层调用 VMManagement 的 native 方法
→ PlatformComponent.RUNTIME(sun.management.PlatformComponent 枚举)
→ 将实现类注册到 PlatformMBeanServer,对外以 JMX 代理形态暴露要点:
- 组件注册:
PlatformComponent枚举定义了平台管理的全部组件(RUNTIME、MEMORY、MEMORY_POOL、THREAD、GARBAGE_COLLECTOR、OPERATING_SYSTEM、CLASS_LOADING、COMPILATION等),每个组件持有其 MXBean 接口类型、域名(java.lang)、类型名(Runtime/Memory等)。 getMXBean()负责在PlatformMBeanServer中注册/查找对应 MBean 并返回客户端视图;JDK 9 之后实现类本身直接作为ManagementFactory的返回值(避免代理开销),PlatformMBeanServer仍保留完整注册用于 JMX 远程访问。- 通过 JMX 拿到的是符合 MXBean 规范的代理对象,而
ManagementFactory直接返回实现类——两者的数据源一致,只是访问途径不同。
② PlatformMBeanServer 的创建
// ManagementFactoryHelper(OpenJDK 21 简化实现)
private static volatile PlatformMBeanServer platformMBeanServer;
static synchronized PlatformMBeanServer getPlatformMBeanServer() {
if (platformMBeanServer == null) {
platformMBeanServer = MBeanServerFactory.createJMXMPConnectorServer... // 仅注册场景
platformMBeanServer = new PlatformMBeanServer(); // 内部实现
}
return platformMBeanServer;
}经典创建链路(JMX 规范路径):
// 规范路径:MBeanServerFactory → MBeanServerBuilder → JmxMBeanServer
MBeanServer mbs = MBeanServerFactory.newMBeanServer(DEFAULT_DOMAIN, null);
// → MBeanServerBuilder.newMBeanServer(defaultDomain, outer, delegate)
// → JmxMBeanServer.newMBeanServer(defaultDomain, outer, delegate)- 单例:
PlatformMBeanServer是懒加载的进程级单例,全 JVM 共享同一MBeanServer实例,所有平台 MXBean 都注册在它的默认域(DefaultDomain)下。 JmxMBeanServer:真正执行注册/查询的服务器实现,内部持有MBeanServerDelegate(记录getMBeanServerId/getSpecificationVersion等元数据)与Repository(MBean 注册表,用树形结构按域名组织)。- 可插拔:
MBeanServerBuilder允许第三方通过MBeanServerBuilder系统属性替换默认实现,实现拦截/包装层(这是 JMX 规范预留的扩展点)。
③ RuntimeMXBean.getInputArguments() 的 JVM 参数
// RuntimeImpl.getInputArguments()
public List<String> getInputArguments() {
return ManagementFactoryHelper.getVmArguments(); // 内部列表
}
// sun.management.VMManagement 接口定义
native List<String> getVmArguments();- native 数据源:
getVmArguments的 JVM 实现直接读取Arguments子系统保存的命令行参数(含-X/-XX选项),返回进程启动时的完整参数列表。 - 对应关系:
getInputArguments()返回启动参数(不含java主类名与类路径之前的java命令本身),getClassPath()返回java.class.path系统属性,getSystemProperties()返回全部System.getProperties()的快照。 - 该列表在 JVM 生命周期内不可变,
RuntimeImpl缓存在构造时创建的List<String>中,之后每次调用直接返回。
④ MemoryMXBean.getHeapMemoryUsage() 的内存快照
// MemoryImpl.getHeapMemoryUsage()
public MemoryUsage getHeapMemoryUsage() {
return getMemoryUsage0(true); // true → 堆内存
}
// sun.management.MemoryImpl 内部
private native MemoryUsage getMemoryUsage0(boolean heap);JVM 侧实现调用 JMM_GetMemoryUsage 收集器接口,返回的 MemoryUsage 是不可变四元组:
| 字段 | 含义 | 数据来源 |
|---|---|---|
init | JVM 启动时向 OS 申请的初始内存大小 | min capacity |
used | 当前已使用的内存 | 存活对象占用 |
committed | JVM 保证可用的内存(已向 OS 提交) | max capacity 以内 |
max | 可使用的最大内存(-Xmx 等配置) | max capacity |
MemoryUsage的四字段均为long(字节),used <= committed恒成立,max可为-1(表示无上限)。- 堆/非堆区分:
getHeapMemoryUsage()取堆,getNonHeapMemoryUsage()取非堆(Metaspace、CodeCache 等)。两者分别对应 JMM 的JMM_HEAP_0/JMM_NON_HEAP_0统计域。 - 每次调用都是实时快照:native 层即时查询当前 GC 统计,非缓存值。
⑤ MemoryPoolMXBean.getUsage() 的内存池
JVM 的内存被划分为多个内存池(Memory Pool)与内存管理器(Memory Manager),ManagementFactory.getMemoryPoolMXBeans() 返回全部池:
public List<MemoryPoolMXBean> getMemoryPoolMXBeans() {
// 从 PlatformMBeanServer 查询 MemoryPool 域下全部 MBean
}典型 G1 配置下的内存池与 getUsage() 数据:
| 内存池名称 | 类型 | 管理 |
|---|---|---|
CodeHeap 'non-nmethods' | 非堆 | CodeCache(JIT 编译器自身代码) |
CodeHeap 'profiled nmethods' | 非堆 | 已剖析的 JIT 编译代码 |
CodeHeap 'non-profiled nmethods' | 非堆 | 未剖析的 JIT 编译代码 |
Metaspace | 非堆 | 类元数据 |
G1 Eden Space | 堆 | 新生代 Eden |
G1 Survivor Space | 堆 | 新生代 Survivor |
G1 Old Gen | 堆 | 老年代 |
- 每个池的
getUsage()同样返回MemoryUsage四元组,数据来自JMM_GetMemoryPoolUsage。 - 池与 GC 管理器的关系:
getMemoryManagerNames()列出负责该池的 GC(如 Eden 对应G1 Young Generation,Old 对应G1 Old Gen/G1 Full GC)。 - 池的
getCollectionUsage()/getPeakUsage()/getUsageThresholdCount()分别提供 GC 后用量、历史峰值与阈值触发次数,用于监控告警。
⑥ ThreadMXBean.getThreadInfo(long threadId) 的线程信息
// ThreadImpl.getThreadInfo(long)
public ThreadInfo getThreadInfo(long id) {
long[] ids = new long[] { id };
return getThreadInfo(ids, 0)[0]; // stackTraceDepth = 0 → 不取栈帧
}
// sun.management.ThreadImpl 内部
private native ThreadInfo getThreadInfo0(long threadId, int stackTraceDepth,
Object[] lockInfo, Object[] threadMonitor);getThreadInfo0由 JVM 通过JMM_GetThreadInfo填充,核心字段:
| 字段 | 含义 |
|---|---|
threadState | 线程状态(NEW / RUNNABLE / BLOCKED / WAITING / TIMED_WAITING / TERMINATED) |
lockName | 线程阻塞/等待的锁对象描述 |
lockOwnerId / lockOwnerName | 当前持有锁的线程 |
blockedCount / blockedTime | 进入阻塞的累计次数与时间 |
waitedCount / waitedTime | 等待通知的累计次数与时间 |
stackTraceDepth = 0时不抓取栈帧(快),getThreadInfo(id, maxDepth)可指定栈深度获取StackTraceElement[]。- 启用时间统计需要
setThreadCpuTimeEnabled(true),blockedTime/waitedTime在未启用时返回-1。 getThreadInfo失败(线程已销毁)返回null,调用方需判空。
⑦ ThreadMXBean.dumpAllThreads(boolean, boolean) 的线程转储
// ThreadImpl.dumpAllThreads(lockedMonitors, lockedSynchronizers)
public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers) {
return dumpAllThreads(lockedMonitors, lockedSynchronizers,
Integer.MAX_VALUE); // 默认全深度
}
private ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers, int maxDepth) {
long[] ids = getAllThreadIds(); // JMM_GetAllThreads:所有存活线程
return getThreadInfo(ids, lockedMonitors, lockedSynchronizers, maxDepth);
}实现三步骤:
- 枚举线程:
getAllThreadIds()走JMM_GetAllThreadsnative 拿到当前全部存活线程 id。 - 批量抓取:
getThreadInfo(allIds, lockedMonitors, lockedSynchronizers, maxDepth)一次性抓取所有线程的状态、栈帧与锁信息。 - 锁信息展开:
lockedMonitors = true时额外收集每个线程持有的对象监视器(MonitorInfo[]),lockedSynchronizers = true时收集持有的并发同步器(LockInfo[],如ReentrantLock/ReentrantReadWriteLock等实现Lock接口的同步器)。
dumpAllThreads 是线程转储(jstack)的编程等价物:jstack 走 Thread-Dump 事件,而 dumpAllThreads 走 JMX,二者数据同源但入口不同。
⑧ OperatingSystemMXBean.getSystemLoadAverage()
// OperatingSystemImpl.getSystemLoadAverage()
public double getSystemLoadAverage() {
return getSystemLoadAverage0();
}
// sun.management.OperatingSystemImpl
private native double getSystemLoadAverage0();- 语义:返回最近 1 分钟的系统平均负载(所有 CPU 上可运行线程的平均数,不是 CPU 使用率),与 Linux 的
uptime输出一致。 - Linux / macOS:native 调用
getloadavg()系统调用获取 1 / 5 / 15 分钟负载,取 1 分钟值。 - Windows:无对应系统调用,返回
-1表示不支持。 - 除了负载,
OperatingSystemMXBean(以及com.sun.management.OperatingSystemMXBean扩展)还通过getSystemCpuLoad()/getProcessCpuLoad()/getCommittedVirtualMemorySize()等 native 方法读取JMM_GetOSValues统计(含psutil级别的 CPU / 内存读数)。
⑨ GarbageCollectorMXBean.getCollectionCount() / getCollectionTime()
// GarbageCollectorImpl(sun.management)
public long getCollectionCount() {
return getCollectionCount0(); // native:GC 事件累计次数
}
public long getCollectionTime() {
return getCollectionTime0(); // native:GC 累计耗时(毫秒)
}- 每个 GC 内存管理器对应一个
GarbageCollectorMXBean,名称即 GC 名称:G1 下为G1 Young Generation(新生代回收)与G1 Full GC(全局回收)。 - 底层数据来自 JVM 的 GC 统计计数器:
JMM_GetGCStat按GCStatInfo(gc_index/gc_time/ 各池gc_used)返回累计值。 getCollectionCount()是自 JVM 启动以来的累计次数(单调递增,不会重置),getCollectionTime()是累计毫秒数;监控 GC 频率时取两次调用的差值。- 搭配
getMemoryPoolNames()(该 GC 负责的池)与MemoryPoolMXBean.getCollectionUsage()(最近一次 GC 后的池用量)可还原单次 GC 的影响。
总结
平台管理 API 的分层结构非常清晰:
| 层 | 组件 | 说明 |
|---|---|---|
| 客户端 | ManagementFactory.getXxxMXBean() | 统一入口,返回 MXBean 接口视图 |
| 暴露 | PlatformMBeanServer | 单例 MBeanServer,所有平台 MBean 注册于此,支持 JMX 远程访问 |
| 实现 | RuntimeImpl / MemoryImpl / ThreadImpl / GarbageCollectorImpl 等 | sun.management 包内实现类,薄封装 |
| 桥接 | sun.management.VMManagement | native 方法声明层 |
| JVM | JMM(JMM_GetMemoryUsage / JMM_GetThreadInfo / JMM_GetGCStat / JMM_GetOSValues) | HotSpot 内部管理接口,统一收集运行时数据 |
ManagementFactory 把"JVM 内部状态"包装成标准 MXBean:内存快照由 JMM_GetMemoryUsage 实时采集,线程信息由 JMM_GetThreadInfo 批量填充,GC 计数由 JMM_GetGCStat 累计统计。理解这条「工厂 → MBeanServer → 实现类 → native → JMM」的链路,就能在 JMX 远程监控、jconsole / jvisualvm 集成或自研监控代理时准确定位数据来源。