最近项目需要对Java进程,堆栈信息,内存,cpu等资源的消耗进行监控,借鉴了git已有的*JPOM java项目管理系统和在线demo网站及对其源码的分析,提炼出了以下几种监控方式。
1.引言
有两种途径可以监控Java进程及对应JVM信息:
一.使用JDK自带rt.jar中 java.lang.management包下的类来管理。java.lang.management包提供了全面的监控和管理工具,包括JVM的监管API、监管API日志、jconsole和其他监控工具、Java管理扩展平台(JMX)等等。
类名 | 描述 |
---|---|
ClassLoadingMXBean | 用于 Java 虚拟机的类加载系统的管理接口。 |
CompilationMXBean | 用于 Java 虚拟机的编译系统的管理接口。 |
GarbageCollectorMXBean | 用于 Java 虚拟机的垃圾回收的管理接口。 |
MemoryManagerMXBean | 内存管理器的管理接口。 |
MemoryMXBean | Java 虚拟机的内存系统的管理接口。 |
MemoryPoolMXBean | 内存池的管理接口。 |
OperatingSystemMXBean | 用于操作系统的管理接口,Java 虚拟机在此操作系统上运行。 |
RuntimeMXBean | Java 虚拟机的运行时系统的管理接口。 |
ThreadMXBean | Java 虚拟机线程系统的管理接口。 |
二 . 使用系统和JVM提供的命令来获取。
如导出堆栈信息: jmap -heap 2576 > JVMHeap.log
进程线程信息:jstack 2576 >> JVMjstack.log
内存使用情况:
window: tasklist /V /FI "pid eq 5027"
linux : top -b -n 1 -p 5027
2. 程序启停, 为进程自定义项目名称
Linux: 启动命令
String command = String.format("nohup java %s %s -Dapplication=%s -Dbasedir=%s %s %s >> %s 2>&1 &",
projectInfoModel.getJvm(),
ProjectInfoModel.getClassPathLib(projectInfoModel),
projectInfoModel.getId(),
projectInfoModel.getAbsoluteLib(),
projectInfoModel.getMainClass(),
projectInfoModel.getArgs(),
projectInfoModel.getAbsoluteLog());
Linux停止
kill %s
Window启动
String command = String.format("javaw %s %s -Dapplication=%s -Dbasedir=%s %s %s >> %s &",
jvm, classPath, tag,
projectInfoModel.getAbsoluteLib(), mainClass, args, projectInfoModel.getAbsoluteLog());
Window停止
taskkill /F /PID %s
tips: -D=value
在虚拟机的系统属性中设置属性名/值对,运行在此虚拟机之上的应用程序可用System.getProperty(“propertyName”)得到value的值。如果value中有空格,则需要用双引号将该值括起来,如-Dname=”space string”。该参数通常用于设置系统级全局变量值,如配置文件路径,应为该属性在程序中任何地方都可访问。
启动命令中添加 -Dapplication=%s 参数来将Project Name加入进程的JVM信息中,后续访问可根据Project Name确定唯一的进程Pid。
Properties properties = virtualMachine.getAgentProperties();
String args = properties.getProperty("sun.jvm.args", "");
if (StrUtil.containsIgnoreCase(args, appTag)) {
return virtualMachine;
}
args = properties.getProperty("sun.java.command", "");
if (StrUtil.containsIgnoreCase(args, appTag)) {
return virtualMachine;
}
3. 操作系统判断
使用System.getProperties() 来获取操作系统配置参数: 如System.getProperty("os.name")获取当前操作系统。
Key | Description of Associated Value | 中文描述 |
---|---|---|
java.version | Java Runtime Environment version | Java 运行时环境版本 |
java.vendor | Java Runtime Environment vendor | Java 运行时环境供应商 |
java.vendor.url | Java vendor URL | Java 供应商的 URL |
java.home | Java installation directory | Java 安装目录 |
java.vm.specification.version | Java Virtual Machine specification version | Java 虚拟机规范版本 |
java.vm.specification.vendor | Java Virtual Machine specification vendor | Java 虚拟机规范供应商 |
java.vm.specification.name | Java Virtual Machine specification name | Java 虚拟机规范名称 |
java.vm.version | Java Virtual Machine implementation version | Java 虚拟机实现版本 |
java.vm.vendor | Java Virtual Machine implementation vendor | Java 虚拟机实现供应商 |
java.vm.name | Java Virtual Machine implementation name | Java 虚拟机实现名称 |
java.specification.version | Java Runtime Environment specification version | Java 运行时环境规范版本 |
java.specification.vendor | Java Runtime Environment specification vendor | Java 运行时环境规范供应商 |
java.specification.name | Java Runtime Environment specification name | Java 运行时环境规范名称 |
java.class.version | Java class format version number | Java 类格式版本号 |
java.class.path | Java class path | Java 类路径 |
java.library.path | List of paths to search when loading libraries | 加载库时搜索的路径列表 |
java.io.tmpdir | Default temp file path | 默认的临时文件路径 |
java.compiler | Name of JIT compiler to use | 要使用的 JIT 编译器的名称 |
java.ext.dirs | Path of extension directory or directories | 一个或多个扩展目录的路径 |
os.name | Operating system name | 操作系统的名称 |
os.arch | Operating system architecture | 操作系统的架构 |
os.version | Operating system version | 操作系统的版本 |
file.separator | File separator ("/" on UNIX) | 文件分隔符(在 UNIX 系统中是“/”) |
path.separator | Path separator (":" on UNIX) | 路径分隔符(在 UNIX 系统中是“:”) |
line.separator | Line separator ("\n" on UNIX) | 行分隔符(在 UNIX 系统中是“/n”) |
user.name | User's account name | 用户的账户名称 |
user.home | User's home directory | 用户的主目录 |
user.dir | User's current working directory | 用户的当前工作目录 |
或者使用OperatingSystemMXBean系统类来获取
OperatingSystemMXBean op = ManagementFactory.getOperatingSystemMXBean();
System.out.println("Architecture: " + op.getArch());
System.out.println("Processors: " + op.getAvailableProcessors());
System.out.println("System name: " + op.getName());
System.out.println("System version: " + op.getVersion());
System.out.println("Last minute load: " + op.getSystemLoadAverage());
4. 获取进程信息
Window : tasklist /V | findstr java
Linux: top -b -n 1 | grep java
通过 VirtualMachine.list() 取得JVM进程描述信息对象
List<VirtualMachineDescriptor> descriptorList = VirtualMachine.list();
5. 内存,CPU信息
Window:
使用命令 tasklist /V /FI "pid eq 5027" 获得进程的内存使用信息,结合OperatingSystemMXBean获取操作系统的内存等的使用情况来分析;
Linux:
top -b -n 1 -p 5027
6. 堆内存信息
使用 MemoryMXBean获取堆内存和非堆内存(方法区)
MemoryMXBean mem = ManagementFactory.getMemoryMXBean();
//堆内存
MemoryUsage memory = memoryMXBean.getHeapMemoryUsage();
//非堆内存
MemoryUsage nonHeapMemoryUsage = memoryMXBean.getNonHeapMemoryUsage();
7. 端口信息
window: netstat -nao -p tcp | findstr /V "CLOSE_WAIT" | findstr 2576
linux : netstat -antup | grep 2576 |grep -v "CLOSE_WAIT" | head -20
8. 线程信息
ThreadMXBean thread = ManagementFactory.getThreadMXBean();
System.out.println("ThreadCount: " + thread.getThreadCount());
System.out.println("AllThreadIds: " + thread.getAllThreadIds());
System.out.println("CurrentThreadUserTime: " + thread.getCurrentThreadUserTime());
9. MXBean使用样例
9.1 根据pid获取jvm对象
VirtualMachine virtualMachine = VirtualMachine.attach(Integer.toString(pid));
9.2 根据jvm对象获取jmx服务
public static JMXServiceURL getJMXServiceURL(VirtualMachine virtualMachine) throws IOException, AgentLoadException, AgentInitializationException {
String address = virtualMachine.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress");
if (address != null) {
return new JMXServiceURL(address);
}
int pid = Convert.toInt(virtualMachine.id());
address = ConnectorAddressLink.importFrom(pid);
if (address != null) {
return new JMXServiceURL(address);
}
String agent = getManagementAgent();
virtualMachine.loadAgent(agent);
address = virtualMachine.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress");
if (address != null) {
return new JMXServiceURL(address);
}
return null;
}
9.3. 使用MXBean代理获取具体管理工具
/**
* 访问指定程序的 MXBean
*/
public static <T extends PlatformManagedObject> T visitMBean(int pid, Class<T> clazz) throws Exception {
//第一种直接调用同一 Java 虚拟机内的 MXBean 中的方法。
// RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean();
// String vendor1 = mxbean.getVmVendor();
// System.out.println("vendor1:" + vendor1);
//第二种使用 MXBean 代理
VirtualMachine virtualMachine = VirtualMachine.attach(Integer.toString(pid));
JMXServiceURL jmxServiceURL = JVMUtil.getJMXServiceURL(virtualMachine);
if (jmxServiceURL == null) {
return null;
}
JMXConnector jmxConnector = JMXConnectorFactory.connect(jmxServiceURL, null);
MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection();
// return ManagementFactory.newPlatformMXBeanProxy(mBeanServerConnection, ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class);
// ManagementFactory.newPlatformMXBeanProxy(mBeanServerConnection, mxBeanName, clazz);
return ManagementFactory.getPlatformMXBean(mBeanServerConnection, clazz);
}
/**
* 访问指定程序的 MXBean
*/
public static <T extends PlatformManagedObject> List<T> visitMBeans(int pid, Class<T> clazz) throws Exception {
//第一种直接调用同一 Java 虚拟机内的 MXBean 中的方法。
// RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean();
// String vendor1 = mxbean.getVmVendor();
// System.out.println("vendor1:" + vendor1);
//第二种使用 MXBean 代理
VirtualMachine virtualMachine = VirtualMachine.attach(Integer.toString(pid));
JMXServiceURL jmxServiceURL = JVMUtil.getJMXServiceURL(virtualMachine);
if (jmxServiceURL == null) {
return null;
}
JMXConnector jmxConnector = JMXConnectorFactory.connect(jmxServiceURL, null);
MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection();
return ManagementFactory.getPlatformMXBeans(mBeanServerConnection, clazz);
}
9.4 访问MXBean demo
ThreadMXBean threadMXBean = (ThreadMXBean) visitMBean(pid, clazz);
long[] threadIds = threadMXBean.getAllThreadIds();
System.out.println("ThreadCount: " + threadMXBean.getThreadCount());
System.out.println("AllThreadIds: " + threadMXBean.getAllThreadIds());
System.out.println("CurrentThreadUserTime: " + threadMXBean.getCurrentThreadUserTime());
// for (int i = 0; i < threadIds.length; i++) {
// ThreadInfo info = threadMXBean.getThreadInfo(threadIds[i]);
// System.out.println(info);
// }
List<GarbageCollectorMXBean> collectorMXBeanList2 = visitMBeans(pid, GarbageCollectorMXBean.class);
System.out.println(collectorMXBeanList2);
for(GarbageCollectorMXBean GarbageCollectorMXBean : collectorMXBeanList2){
System.out.println("gc name:" + GarbageCollectorMXBean.getName());
System.out.println("CollectionCount:" + GarbageCollectorMXBean.getCollectionCount());
System.out.println("CollectionTime" + GarbageCollectorMXBean.getCollectionTime());
}
9.6 demo
import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.lang.management.*;
import java.util.List;
/**
* java.lang.management包 监控
*/
public class JVMManagementDemo {
/**
* {@link ManagementFactory}
* ClassLoadingMXBean 用于 Java 虚拟机的类加载系统的管理接口。
* CompilationMXBean 用于 Java 虚拟机的编译系统的管理接口。
* GarbageCollectorMXBean 用于 Java 虚拟机的垃圾回收的管理接口。
* MemoryManagerMXBean 内存管理器的管理接口。
* MemoryMXBean Java 虚拟机的内存系统的管理接口。
* MemoryPoolMXBean 内存池的管理接口。
* OperatingSystemMXBean 用于操作系统的管理接口,Java 虚拟机在此操作系统上运行。
* RuntimeMXBean Java 虚拟机的运行时系统的管理接口。
* ThreadMXBean Java 虚拟机线程系统的管理接口。
*
* @cmd
* start : javaw -jar -Xms10M -Dapplication=simpleDemo simpleDemo-1.0-SNAPSHOT.jar
* stop : taskkill /F /PID 1201
*
* @param args
*/
public static void main(String[] args) throws Exception {
// 获取本机信息
showJvmInfo();
showMemoryInfo();
showSystem();
showClassLoading();
showCompilation();
showThread();
showGarbageCollector();
showMemoryManager();
showMemoryPool();
// 代理获取 远程 进程信息
/* String tag = "simpleDemo";
int pid = AbstractProjectCommander.getInstance().getPid(tag);*/
int pid = 12345;
Class clazz = ThreadMXBean.class;
ThreadMXBean threadMXBean = (ThreadMXBean) visitMBean(pid, clazz);
long[] threadIds = threadMXBean.getAllThreadIds();
System.out.println("ThreadCount: " + threadMXBean.getThreadCount());
System.out.println("AllThreadIds: " + threadMXBean.getAllThreadIds());
System.out.println("CurrentThreadUserTime: " + threadMXBean.getCurrentThreadUserTime());
// for (int i = 0; i < threadIds.length; i++) {
// ThreadInfo info = threadMXBean.getThreadInfo(threadIds[i]);
// System.out.println(info);
// }
List<GarbageCollectorMXBean> collectorMXBeanList2 = visitMBeans(pid, GarbageCollectorMXBean.class);
System.out.println(collectorMXBeanList2);
for(GarbageCollectorMXBean GarbageCollectorMXBean : collectorMXBeanList2){
System.out.println("gc name:" + GarbageCollectorMXBean.getName());
System.out.println("CollectionCount:" + GarbageCollectorMXBean.getCollectionCount());
System.out.println("CollectionTime" + GarbageCollectorMXBean.getCollectionTime());
}
}
/**
* Java 虚拟机的运行时系统
*/
public static void showJvmInfo() {
RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean();
String vendor = mxbean.getVmVendor();
System.out.println("jvm name:" + mxbean.getVmName());
System.out.println("jvm version:" + mxbean.getVmVersion());
System.out.println("jvm bootClassPath:" + mxbean.getBootClassPath());
System.out.println("jvm start time:" + mxbean.getStartTime());
}
/**
* Java 虚拟机的内存系统
*/
public static void showMemoryInfo() {
MemoryMXBean mem = ManagementFactory.getMemoryMXBean();
MemoryUsage heap = mem.getHeapMemoryUsage();
System.out.println("Heap committed:" + heap.getCommitted() + " init:" + heap.getInit() + " max:"
+ heap.getMax() + " used:" + heap.getUsed());
}
/**
* Java 虚拟机在其上运行的操作系统
*/
public static void showSystem() {
OperatingSystemMXBean op = ManagementFactory.getOperatingSystemMXBean();
System.out.println("Architecture: " + op.getArch());
System.out.println("Processors: " + op.getAvailableProcessors());
System.out.println("System name: " + op.getName());
System.out.println("System version: " + op.getVersion());
System.out.println("Last minute load: " + op.getSystemLoadAverage());
}
/**
* Java 虚拟机的类加载系统
*/
public static void showClassLoading(){
ClassLoadingMXBean cl = ManagementFactory.getClassLoadingMXBean();
System.out.println("TotalLoadedClassCount: " + cl.getTotalLoadedClassCount());
System.out.println("LoadedClassCount" + cl.getLoadedClassCount());
System.out.println("UnloadedClassCount:" + cl.getUnloadedClassCount());
}
/**
* Java 虚拟机的编译系统
*/
public static void showCompilation(){
CompilationMXBean com = ManagementFactory.getCompilationMXBean();
System.out.println("TotalCompilationTime:" + com.getTotalCompilationTime());
System.out.println("name:" + com.getName());
}
/**
* Java 虚拟机的线程系统
*/
public static void showThread(){
ThreadMXBean thread = ManagementFactory.getThreadMXBean();
System.out.println("ThreadCount: " + thread.getThreadCount());
System.out.println("AllThreadIds: " + thread.getAllThreadIds());
System.out.println("CurrentThreadUserTime: " + thread.getCurrentThreadUserTime());
//......还有其他很多信息
}
/**
* Java 虚拟机中的垃圾回收器。
*/
public static void showGarbageCollector(){
List<GarbageCollectorMXBean> gc = ManagementFactory.getGarbageCollectorMXBeans();
for(GarbageCollectorMXBean GarbageCollectorMXBean : gc){
System.out.println("GC name:" + GarbageCollectorMXBean.getName());
System.out.println("CollectionCount:" + GarbageCollectorMXBean.getCollectionCount());
System.out.println("CollectionTime" + GarbageCollectorMXBean.getCollectionTime());
}
}
/**
* Java 虚拟机中的内存管理器
*/
public static void showMemoryManager(){
List<MemoryManagerMXBean> mm = ManagementFactory.getMemoryManagerMXBeans();
for(MemoryManagerMXBean eachmm: mm){
System.out.println("name:" + eachmm.getName());
System.out.println("MemoryPoolNames:" + eachmm.getMemoryPoolNames().toString());
}
}
/**
* Java 虚拟机中的内存池
*/
public static void showMemoryPool(){
List<MemoryPoolMXBean> mps = ManagementFactory.getMemoryPoolMXBeans();
for(MemoryPoolMXBean mp : mps){
System.out.println("name:" + mp.getName());
System.out.println("CollectionUsage:" + mp.getCollectionUsage());
System.out.println("type:" + mp.getType());
}
}
/**
* 访问指定程序的 MXBean
*/
public static <T extends PlatformManagedObject> T visitMBean(int pid, Class<T> clazz) throws Exception {
//第一种直接调用同一 Java 虚拟机内的 MXBean 中的方法。
// RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean();
// String vendor1 = mxbean.getVmVendor();
// System.out.println("vendor1:" + vendor1);
//第二种使用 MXBean 代理
VirtualMachine virtualMachine = VirtualMachine.attach(Integer.toString(pid));
JMXServiceURL jmxServiceURL = JVMUtil.getJMXServiceURL(virtualMachine);
if (jmxServiceURL == null) {
return null;
}
JMXConnector jmxConnector = JMXConnectorFactory.connect(jmxServiceURL, null);
MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection();
// return ManagementFactory.newPlatformMXBeanProxy(mBeanServerConnection, ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class);
// ManagementFactory.newPlatformMXBeanProxy(mBeanServerConnection, mxBeanName, clazz);
return ManagementFactory.getPlatformMXBean(mBeanServerConnection, clazz);
}
/**
* 访问指定程序的 MXBean
*/
public static <T extends PlatformManagedObject> List<T> visitMBeans(int pid, Class<T> clazz) throws Exception {
//第一种直接调用同一 Java 虚拟机内的 MXBean 中的方法。
// RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean();
// String vendor1 = mxbean.getVmVendor();
// System.out.println("vendor1:" + vendor1);
//第二种使用 MXBean 代理
VirtualMachine virtualMachine = VirtualMachine.attach(Integer.toString(pid));
JMXServiceURL jmxServiceURL = JVMUtil.getJMXServiceURL(virtualMachine);
if (jmxServiceURL == null) {
return null;
}
JMXConnector jmxConnector = JMXConnectorFactory.connect(jmxServiceURL, null);
MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection();
return ManagementFactory.getPlatformMXBeans(mBeanServerConnection, clazz);
}
}