最近項目需要對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
在虛擬機的系統屬性中設置屬性名/值對,運行在此虛擬機之上的應用程序可用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);
}
}