如何从外部查询已知PID的运行中JVM已加载的命名JPMS模块?
查询运行中JVM已加载的命名JPMS模块的简洁方法
当然有更省心的方法!不用费劲去解析jcmd <pid> VM.class_hierarchy的冗长输出,Java 9+早就为JPMS模块查询提供了更直接的工具和方案:
1. 最推荐:用jcmd的VM.module命令
这是官方专门为模块信息查询设计的命令,简单到一步到位。在终端直接运行:
jcmd <pid> VM.module
它会输出所有已加载模块的规整信息,包括:
- 命名模块的名称、版本、模块路径、加载状态
- 明确标记的
unnamed module(你提到的未命名模块)
完全不需要自己做复杂的文本解析,一眼就能区分出所有命名JPMS模块。
2. 可视化选择:使用JConsole
如果你偏好图形化界面,JConsole能直观展示模块列表:
- 启动
jconsole,在连接窗口选择目标PID对应的JVM实例 - 连接成功后切换到Modules标签页,就能看到所有已加载模块的分类列表,命名模块和未命名模块清晰区分,还能查看每个模块的依赖、导出包等细节
3. 自动化场景:用Attach API编写工具
如果需要批量或自动化查询,可以借助Java Attach API写一个轻量工具。核心逻辑是附加到目标JVM后,通过模块API获取命名模块:
import com.sun.tools.attach.VirtualMachine; import java.lang.module.ModuleDescriptor; import java.util.Set; import java.util.stream.Collectors; public class NamedModuleLister { public static void main(String[] args) throws Exception { if (args.length == 0) { System.out.println("请传入目标JVM的PID"); return; } String pid = args[0]; VirtualMachine vm = VirtualMachine.attach(pid); try { // 获取启动层中的所有命名模块 Set<Module> namedModules = ModuleLayer.boot().modules().stream() .filter(Module::isNamed) .collect(Collectors.toSet()); namedModules.forEach(module -> { ModuleDescriptor desc = module.getDescriptor(); System.out.printf("模块名: %s,版本: %s%n", desc.name(), desc.version().orElse("无版本信息")); }); } finally { vm.detach(); } } }
注意:运行这个工具需要依赖JDK的相关模块(如jdk.attach),且需要足够的系统权限来附加到目标JVM。
总结
日常临时查询优先用jcmd <pid> VM.module,简洁高效零额外工作;可视化需求选JConsole;自动化或批量场景可以基于Attach API封装工具。
内容的提问来源于stack exchange,提问作者Hamid Nazari
相关产品推荐
相关产品推荐

