
JVMM(JVM Monitor)是一個提供Java虛擬機和操作系統服務式監控的工具,擁有豐富的數據採集功能:OS(內存、CPU、磁盤狀態及IO、網卡狀態及IO等)、 JVM(內存、線程、線程池、內存池、GC、類加載器等),還提供生成火焰圖、Java代碼熱更、反編譯等功能。適合用於服務健康監控、程序調優、問題排查、性能測試等場景。
請前往releases下載最新版的jvmm,然後將其解壓
小Tips:Jvmm 部分功能依賴於本地環境中的jdk,請確保你的環境中安裝的是jdk 而不只是jre,簡單驗證:在你的環境中執行
jps -l, 如果可正常執行並輸出結果則表示環境OK,否則可能無法運行Jvmm。
首先執行下面指令生成服務jar包
java -jar jvmm.jar -m jar -s然後啟動server,啟動時請注意你的jdk版本
# 启动server,jdk 8使用下面命令
java -jar jvmm-server.jar
# jdk 9+ 为确保成功运行建议使用下面命令
java -jar --add-opens java.base/jdk.internal.loader=ALL-UNNAMED
--add-opens jdk.zipfs/jdk.nio.zipfs=ALL-UNNAMED
--add-opens java.base/java.net=ALL-UNNAMED
--add-opens java.management/sun.management=ALL-UNNAMED
jvmm-server.jar如果啟動成功Jvmm Server 將會默認運行在5010端口,然後你需要在當前目錄新起一個窗口執行:
java -jar jvmm.jar -m client -a 127.0.0.1:5010如果連接server 成功那麼你就進入了客戶端模式,你可以輸入下面指令去採集進程數據,當然輸入help可以查看該模式下所有可執行指令的使用方法。
info -t process這裡提供了Jvmm client模式下採集的數據樣例,Jvmm提供的功能遠不止如此,更多功能請閱讀Jvmm 使用文檔。
Jvmm的核心數據採集功能在core模塊,提供的服務式功能在server模塊,根據你的使用場景可選擇下面兩種使用方式:
core模塊二次開發(功能更全) 首先你需要了解server 能幹嘛? server提供了三種服務模式,在使用之前你需要選擇哪種模式更適合你,下面簡單介紹一下三種服務模式:
任何一種服務模式都離不開配置文件jvmm.yml,通過server.type來配置你選擇了哪個模式或哪幾個模式, 它們可以同時運行,各個模式的具體配置分別對應server.jvmm , server.http , server.sentinel 。
server :
type : jvmm,http,sentinel # 支持同时开启多种模式
jvmm :
# ...
http :
# ...
sentinel :
# ...默認配置請見jvmm.yml,其中配置信息請見配置文件中的註釋。
Jvmm提供了四種方式來啟動你的server:
-javaagent參數)jvmm-server.jar (不支持反編譯和代碼熱更功能)注意! ! !
無論是你用哪種方式啟動Server,如果你的運行環境是jdk 9+以上,為確保成功運行建議在啟動時添加以下JVM參數
--add-opens java.base/jdk.internal.loader=ALL-UNNAMED
--add-opens jdk.zipfs/jdk.nio.zipfs=ALL-UNNAMED
--add-opens java.base/java.net=ALL-UNNAMED
--add-opens java.management/sun.management=ALL-UNNAMED
運行jvmm.jar,選擇attach模式
java -jar jvmm.jar -m attach -c ./jvmm.yml然後會提示你選擇目標進程的序號,選擇後便會在目標進程中啟動server。
如果你已經知道目標進程的pid,你可以直接指定它:
java -jar jvmm.jar -m attach -c ./jvmm.yml -pid 80080
Java Agent方式你需要先生成所需的jar包,使用-a參數指定生成agent :
# 如果你的宿主程序中包含了 SLF4J 的实现(例如 logback),需要在生成时使用 -e 参数排除掉jvmm自带的 slf4j 实现
java -jar jvmm.jar -m jar -a -e logger
# 如果你的宿主程序中没有 SLF4J 的实现,无需排除 logger
java -jar jvmm.jar -m jar -a執行之後會在同級目錄下生成對應的文件: jvmm-agent.jar ,然後在啟動目標程序(假設為app.jar)時添加-javaagent參數,格式如下:
java -javaagent:<jvmm-agent.jar路径>=config=<jvmm.yml路径> -jar your-app.jar
例如:
java -javaagent:/path/jvmm-agent.jar=config=/path/jvmm.yml -jar app.jar為兼容使用外部server 的功能,完整的javaagent格式為:
-javaagent:<jvmm-agent.jar路径>=server=<jvmm-server.jar路径>;config=<jvmm.yml路径>
當你的程序啟動之後Jvmm 就會以Agent的方式啟動

如果你不想依附於任何宿主程序,可以選擇單獨啟動一個Jvmm server,比如在監控物理機器的場景下。
首先需要生成啟動的jar依賴,使用-s參數指定生成server :
java -jar jvmm.jar -s執行結束後會在同級目錄生成一個jvmm-server.jar ,然後啟動server,啟動時請注意你的jdk版本
# 启动server,jdk 8使用下面命令
java -jar jvmm-server.jar
# jdk 9+ 为确保成功运行建议使用下面命令
java -jar --add-opens java.base/jdk.internal.loader=ALL-UNNAMED
--add-opens jdk.zipfs/jdk.nio.zipfs=ALL-UNNAMED
--add-opens java.base/java.net=ALL-UNNAMED
--add-opens java.management/sun.management=ALL-UNNAMED
jvmm-server.jar如果你想在自己的項目工程中使用server,需要先引入maven依賴
< dependencies >
< dependency >
< groupId >io.github.tzfun.jvmm</ groupId >
< artifactId >jvmm-server</ artifactId >
< version >${jvmm-version}</ version >
</ dependency >
<!-- jvmm日志依赖,如果你的项目中有 SLF4J、Log4J2、Log4J中任意一个依赖,可以去掉此依赖 -->
< dependency >
< groupId >io.github.tzfun.jvmm</ groupId >
< artifactId >jvmm-logger</ artifactId >
< version >${jvmm-version}</ version >
</ dependency >
</ dependencies >一行代碼啟動server
import org . beifengtz . jvmm . server . ServerBootstrap ;
public class Jvmm {
public static void main ( String [] args ) {
ServerBootstrap . getInstance (). start ();
}
}當然上面的啟動方式會使用默認的配置,一般都需要自定義配置, getInstance方法可以傳入一個org.beifengtz.jvmm.server.entity.conf.Configuration對象, 通過構造Configuration 既可以實現自定義配置。
使用JvmmConnector 連接Jvmm Server ServerConveyDemo.java
當Server以jvmm或http模式啟動之後,你可以遠程調用內置的接口。

Jvmm Service提供了以下API接口:
| Type | Data | Description |
|---|---|---|
| JVMM_COLLECT_SYS_INFO | / | 採集操作系統信息 |
| JVMM_COLLECT_SYS_MEMORY_INFO | / | 採集操作系統內存數據 |
| JVMM_COLLECT_SYS_FILE_INFO | / | 採集操作系統磁盤分區使用情況數據 |
| JVMM_COLLECT_PROCESS_INFO | / | 採集當前進程數據 |
| JVMM_COLLECT_DISK_INFO | / | 採集物理機磁盤數據 |
| JVMM_COLLECT_DISK_IO_INFO | / | 採集物理機磁盤IO及吞吐量數據 |
| JVMM_COLLECT_CPU_INFO | / | 採集物理機CPU負載數據 |
| JVMM_COLLECT_NETWORK_INFO | / | 採集物理機網卡信息及IO數據 |
| JVMM_COLLECT_PORT_STATUS | JsonArray,其元素為端口號 | 採集物理機器端口使用情況 |
| JVMM_COLLECT_JVM_CLASSLOADING_INFO | / | 採集JVM類加載信息 |
| JVMM_COLLECT_JVM_CLASSLOADER_INFO | / | 採集JVM類加載器信息 |
| JVMM_COLLECT_JVM_COMPILATION_INFO | / | 採集JVM編譯信息 |
| JVMM_COLLECT_JVM_GC_INFO | / | 採集JVM垃圾收集器信息 |
| JVMM_COLLECT_JVM_MEMORY_MANAGER_INFO | / | 採集JVM內存管理器信息 |
| JVMM_COLLECT_JVM_MEMORY_POOL_INFO | / | 採集JVM內存池信息 |
| JVMM_COLLECT_JVM_MEMORY_INFO | / | 採集JVM內存使用情況 |
| JVMM_COLLECT_JVM_THREAD_INFO | / | 採集JVM線程統計數據 |
| JVMM_COLLECT_JVM_THREAD_STACK | 見ThreadInfoDTO | 採集指定JVM線程堆棧數據 |
| JVMM_COLLECT_JVM_THREAD_DETAIL | JsonArray,其元素為線程ID | 採集JVM線程詳情信息(CPU Time、Block Time、Locks等) |
| JVMM_COLLECT_JVM_THREAD_POOL | JsonObject,其屬性為:classLoaderHash(String), clazz(String), instanceField(String), field(String) | 採集JVM線程池信息 |
| JVMM_COLLECT_JVM_THREAD_ORDERED_CPU_TIME | JsonObject,其屬性為:type(String, stack|info), durationSeconds(int) | 採集JVM線程在一定時間內CPU佔用時間情況 |
| JVMM_COLLECT_JVM_DUMP_THREAD | / | dump所有線程堆棧數據 |
| JVMM_COLLECT_BATCH | CollectionType[] | 根據選項批量採集數據 |
| JVMM_EXECUTE_GC | / | 執行gc |
| JVMM_EXECUTE_JAVA_PROCESS | / | 列出所有Java進程 |
| JVMM_EXECUTE_JVM_TOOL | String | 執行jvm tool命令 |
| JVMM_EXECUTE_JAD | JsonObject,其屬性為:className(String), methodName(String) | 代碼反編譯(僅支持agent) |
| JVMM_EXECUTE_LOAD_PATCH | JsonArray,其元素為PatchDTO | 代碼熱更,當指定ClassLoader的hash時只針對於改ClassLoader加載的類進行熱更 |
| JVMM_EXECUTE_SWITCHES_GET | / | 獲取採集開關信息 |
| JVMM_EXECUTE_SWITCHES_SET | JsonObject,其屬性為:names(Switches[]), open(boolean) | 設置採集開關 |
| JVMM_PROFILER_SAMPLE | 見ProfilerSampleDTO | 生成火焰圖 |
| JVMM_PROFILER_EXECUTE | String | 執行profiler命令,見async-profiler |
| JVMM_PROFILER_START | 見ProfilerSampleDTO,其中只有eventcounterinteval字段有效 | 執行profiler開始採樣命令 |
| JVMM_PROFILER_STOP | String,ProfilerSampleDTO中的format字段,可選值為htmltxtjfr | 執行profiler結束採樣並導出文件命令 |
| JVMM_PROFILER_STATUS | / | 獲取當前profiler狀態 |
| JVMM_PROFILER_LIST_EVENTS | / | 獲取當前環境支持的profiler events |
| JVMM_SERVER_SHUTDOWN | String | 關閉服務,data為服務類型 |

Http Service提供了以下API接口:
| Uri | 方法 | 參數 | Body | 描述 |
|---|---|---|---|---|
| /collect/process | GET | / | / | 採集進程信息 |
| /collect/disk | GET | / | / | 採集物理機磁盤數據 |
| /collect/disk_io | GET | / | / | 採集物理機磁盤IO及吞吐量數據 |
| /collect/cpu | GET | / | / | 採集物理機CPU負載數據 |
| /collect/network | GET | / | / | 採集物理機網卡信息及IO數據 |
| /collect/sys | GET | / | / | 採集操作系統信息 |
| /collect/sys/memory | GET | / | / | 採集操作系統內存數據 |
| /collect/sys/file | GET | / | / | 採集操作系統磁盤分區使用情況數據 |
| /collect/port | GET | ports(int[]) | / | 採集操作系統端口占用情況 |
| /collect/jvm/classloading | GET | / | / | 採集JVM類加載信息 |
| /collect/jvm/classloader | GET | / | / | 採集JVM類加載器信息 |
| /collect/jvm/compilation | GET | / | / | 採集JVM編譯信息 |
| /collect/jvm/gc | GET | / | / | 採集JVM垃圾收集器信息 |
| /collect/jvm/memory_manager | GET | / | / | 採集JVM內存管理器信息 |
| /collect/jvm/memory_pool | GET | / | / | 採集JVM內存池信息 |
| /collect/jvm/memory | GET | / | / | 採集JVM內存使用情況 |
| /collect/jvm/thread | GET | / | / | 採集JVM線程統計數據 |
| /collect/jvm/thread_stack | POST | / | 見ThreadInfoDTO | 採集指定JVM線程堆棧數據 |
| /collect/jvm/dump_thread | GET | / | / | dump所有線程堆棧數據 |
| /collect/jvm/thread_ordered_cpu_time | GET | type(String, stack|info), durationSeconds(int) | / | 採集JVM線程在一定時間內CPU佔用時間情況 |
| /collect/jvm/thread_detail | GET | id(long[]) | / | 採集JVM線程詳情信息(CPU Time、Block Time、Locks等) |
| /collect/jvm/thread_pool | GET | classLoaderHash(String), clazz(String), instanceField(String), field(String) | / | 採集JVM線程池信息 |
| /collect/by_options | GET | options(CollectionType[]) | 根據選項批量採集數據 | |
| /execute/gc | GET | / | / | 執行gc |
| /execute/jps | GET | / | / | 列出所有Java進程 |
| /execute/jvm_tool | POST | / | command(String) | 執行jvm tool命令 |
| /execute/jad | GET | className(String), methodName(String) | / | 代碼反編譯(僅支持agent) |
| /execute/load_patch | POST | / | JsonArray,其元素為PatchDTO | 代碼熱更,當指定ClassLoader的hash時只針對於改ClassLoader加載的類進行熱更 |
| /execute/get_switches | GET | / | / | 獲取採集開關信息 |
| /execute/set_switches | GET | names(Switches[]), open(boolean) | / | 設置採集開關 |
| /profiler/flame_graph | POST | / | 見ProfilerSampleDTO | 生成火焰圖 |
| /profiler/start | POST | / | 見ProfilerSampleDTO,其中只有eventcounterinteval字段有效 | 執行profiler開始採樣命令 |
| /profiler/stop | POST | / | String,ProfilerSampleDTO中的format字段,可選值為htmltxtjfr | 執行profiler結束採樣並導出文件命令 |
| /profiler/status | GET | / | / | 獲取當前profiler狀態 |
| /profiler/list_events | GET | / | / | 獲取當前環境支持的profiler events |
| /profiler/execute | POST | / | command(String) | 執行profiler命令,見async-profiler |
| /server/shutdown | GET | target(String) | / | 關閉服務,data為服務類型 |

哨兵模式的運作邏輯是定期採集指定數據項然後向訂閱者推送,你需要提供一個可接收數據的訂閱服務(http接口),如果接口訪問需要進行身份認證, 訂閱者Http接口目前僅支持Basic方式認證。
哨兵模式配置
server :
type : sentinel
sentinel :
- subscribers :
# publish jvmm data to custom http server
- type : http
url : http://127.0.0.1:9999/monitor/subscriber
auth :
enable : true
username : 123456
password : 123456
# publish jvmm data to prometheus
- type : prometheus
url : http://127.0.0.1:9090/api/v1/write
auth :
enable : true
username : 123456
password : 123456
interval : 15
tasks :
- process
- disk
- disk_io
- cpu
- port
...總共支持以下採集項:
[
" process " ,
" disk " ,
" disk_io " ,
" cpu " ,
" network " ,
" sys " ,
" sys_memory " ,
" sys_file " ,
" port " ,
" jvm_classloading " ,
" jvm_classloader " ,
" jvm_compilation " ,
" jvm_gc " ,
" jvm_memory " ,
" jvm_memory_manager " ,
" jvm_memory_pool " ,
" jvm_thread " ,
" jvm_thread_stack " ,
" jvm_thread_detail " ,
" jvmm_thread_pool "
]目前僅以下採集項支持Prometheus
[
" process " ,
" disk_io " ,
" cpu " ,
" network " ,
" sys " ,
" sys_memory " ,
" sys_file " ,
" jvm_classloading " ,
" jvm_compilation " ,
" jvm_gc " ,
" jvm_memory " ,
" jvm_memory_pool " ,
" jvm_thread "
]jvmm提供了兩個Grafana模板Dashboard,分別是:node、jvm
node模板是與系統相關監控項的集合,可以幫助你更專注物理機或云主機的監控數據


導入方式:導入Dashboard ID 20430 或導入dashboard-node.json
與此模板配合需要配置以下task:
[
" process " ,
" disk_io " ,
" cpu " ,
" network " ,
" sys " ,
" sys_memory " ,
" sys_file "
]jvm模板是與JVM相關監控項的集合,可以幫助你更專注進程的監控數據


導入方式:導入Dashboard ID 20429 或導入dashboard-jvm.json
與此模板配合需要配置以下task:
[
" process " ,
" jvm_classloading " ,
" jvm_compilation " ,
" jvm_gc " ,
" jvm_memory " ,
" jvm_memory_pool " ,
" jvm_thread "
]如果你想基於Jvmm二次開發,只需要引入core 依賴
< dependency >
< groupId >io.github.tzfun.jvmm</ groupId >
< artifactId >jvmm-core</ artifactId >
< version >${jvmm-version}</ version >
</ dependency >前面Server 提供的所有數據採集功能接口以及其他未提供遠程調用接口的功能接口都能通過一個工廠類獲取到: org.beifengtz.jvmm.core.JvmmFactory
public class Jvmm {
public static void main ( String [] args ) {
// 提供所有的数据采集接口
JvmmCollector collector = JvmmFactory . getCollector ();
// 提供所有的执行接口
JvmmExecutor executor = JvmmFactory . getExecutor ();
// 提供火焰图生成器
JvmmProfiler profiler = JvmmFactory . getProfiler ();
}
}Jvmm客戶端工具提供了一種簡單快捷的遠程調用Jvmm的方式,當然它還承擔了attach server、生成依賴jar等重要的功能。
客戶端工具提供了引導式命令執行功能,即使你不帶任何參數也會以詢問的方式執行,具體用法請使用下面指令查看幫助文檔:
java -jar jvmm.jar -h客戶端工具採集數據示例
生成火焰圖示例

代碼調用示例
自定義Dashboard應用示例

項目內部有些組件是可以脫離項目使用的,輕量且上手簡單
原因是你的環境沒有jdk tools 或者沒配置環境變量,請先確保你的環境中安裝的是jdk而不只是jre,簡單驗證:在你的環境中執行jps -l , 如果可正常執行並輸出結果則表示環境OK。
解決辦法:將你本地jdk 的bin目錄配置為環境變量
如果你在啟動jvmm-server.jar 時報下面錯,原因是你使用了JDK 9及以上版本,在JDK 9+開始Java禁止了部分類的反射訪問。
java.lang.reflect.InaccessibleObjectException: Unable to make field final jdk.internal.loader.URLClassPath jdk.internal.loader.ClassLoaders$AppClassLoader.ucp accessible: module java.base does not "opens jdk.internal.loader" to unnamed module @2d127a61
解決辦法:添加下面幾個虛擬機參數
# JDK 9+ 为确保成功运行建议设置以下几个虚拟机参数
# --add-opens java.base/jdk.internal.loader=ALL-UNNAMED
# --add-opens jdk.zipfs/jdk.nio.zipfs=ALL-UNNAMED
# --add-opens java.base/java.net=ALL-UNNAMED
# --add-opens java.management/sun.management=ALL-UNNAMED
java -jar --add-opens java.base/jdk.internal.loader=ALL-UNNAMED
--add-opens jdk.zipfs/jdk.nio.zipfs=ALL-UNNAMED
--add-opens java.base/java.net=ALL-UNNAMED
--add-opens java.management/sun.management=ALL-UNNAMED
jvmm-server.jar ./jvmm.yml如果你在生成火焰圖時提示No access to perf events. Try --fdtransfer or --all-user option or 'sysctl kernel.perf_event_paranoid=1'性能,你需要開啟這個選項。
sudo systcl -w kernel.perf_event_paranoid=1或者修改sysctl文件
sudo sh -c ' echo "kernel.perf_event_paranoid=1" >> /etc/sysctl.conf '
sudo sysctl -p本工具完全開源免費,創作不易,如果你覺得不錯可以捐贈支持本項目。
捐贈名單:
在使用過程中遇到任何問題,或者對本項目有獨特的見解或建議,歡迎提交issue或私信我
微信:beifeng-tz(添加請備註jvmm )