jvisualvm分析java應用記憶體需要遠端服務上啟動jstatd服務(jmx也有記憶體監控資訊,不過沒有jstatd記憶體資訊詳細),網上各種相關文章大部分都是介紹的簡單模糊,很多要注意的地方沒介紹,真正按着操作的話,各種連不上沒反應,讓人着急!
下面分享個我在項目中分析記憶體時伺服器上啟動jstatd服務的腳本工具,自動安裝jstatd環境,能夠快速啟動關閉jstatd服務。一些需要注意和容易出錯的地方我也會下面指出。
我在伺服器上安裝的是openjdk1.8 ,是以jstatd.sh 腳本裡面自動安裝的jstatd工具也是1.8的,如果是别的版本自己看着改下。
下面進入正題
建立jstatd 腳本
jstatd腳本有2個檔案: 啟動腳本檔案 jstatd.sh 和 權限配置檔案 jstatd.all.policy
[[email protected] jstatd]# ll
total 8
-rwxr-xr-x 1 root root 107 Sep 28 16:03 jstatd.all.policy
-rwxr-xr-x 1 root root 1546 Sep 28 15:51 jstatd.sh
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLxQTM4UzNxUTM4ITOwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
jstatd.all.policy
vi 編輯jstatd.all.policy 權限檔案,内容如下:
grant codebase "file:${java.home}/../lib/tools.jar" {
permission java.security.AllPermission;
};
儲存退出
注意:如果沒有這個檔案,啟動jstatd.sh時會報錯:Could not create remote object ,具體如下:
Could not create remote object
access denied ("java.util.PropertyPermission" "java.rmi.server.ignoreSubClasses" "write")
java.security.AccessControlException: access denied ("java.util.PropertyPermission" "java.rmi.server.ignoreSubClasses" "write")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
at java.security.AccessController.checkPermission(AccessController.java:886)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.System.setProperty(System.java:792)
at sun.tools.jstatd.Jstatd.main(Jstatd.java:139)
jstatd.sh
vi編輯 jstatd.sh 腳本檔案内容如下: (注意,把 xxx.x.xxx.xxx 替換你們自己的伺服器外網ip位址)
#!/bin/bash
CMD=$(basename $0)
OK="[ \e[32mOK\e[0m ]";
FAIL="[\e[31mfail\e[0m]";
# 屬性
HOSTNAME="xxx.x.xxx.xxx";
PORT="1099";
# 運作環境
if [ -z `which jstatd 2>/dev/null` ] ; then
echo -e "backgrounder : yum install -y java-1.8.0-openjdk-devel";
yum install -y java-1.8.0-openjdk-devel >/dev/null && \
echo -e "$OK yum java-1.8.0-openjdk-devel"
fi
help(){
echo -e "[\e[32m[-?|-help\e[0m]"
echo -e " 幫助"
echo -e "[\e[32m[-h host]\e[0m]"
echo -e " host"
echo -e "[\e[32m[-p port]\e[0m]"
echo -e " port"
echo -e "[\e[32m[start|stop]\e[0m]"
echo -e " 啟動|停止"
}
# 擷取參數
while getopts :h:p: opt;
do
case $opt
in
h)HOSTNAME="$OPTARG";
;;
p)PORT="$OPTARG";
;;
?)
help;
exit -1;
;;
esac;
done;
kill_cmd(){
timeout=20
i=0
PID=$(pgrep jstatd|awk -v p=$$ 'p!=$1{print}')
if [[ `kill -0 $PID &>/dev/null;echo $?` = 0 ]] ;then
kill -15 $PID &>/dev/null
echo -n "stop $CMD"
while [[ `kill -0 $PID &>/dev/null;echo $?` = 0 ]] ; do
if [ $i -ge $timeout ] ;then
echo -e $FAIL
return 0
else
echo -n "."
sleep 1
i=`expr $i + 1`
fi
done
echo -e $OK
fi
return 0
}
start_cmd(){
setsid jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=$HOSTNAME -p$PORT &
echo "start $CMD"
return 0
}
##############################################
case "$1" in
'start')
start_cmd
;;
'stop')
kill_cmd
;;
'restart' | '')
kill_cmd && start_cmd
;;
'-?' | '-h' | '-help' | *)
help
;;
esac
注意 權限問題,操作時最好切換到root使用者權限 sudo su,然後記得給啟動腳本執行權限 chmod 755 jstatd.sh
用腳本啟動jstatd服務
确認擁有各種操作權限後,切換到 jstatd.sh 所在目錄
1、啟動jstatd 服務
./jstatd.sh
[[email protected] tools]# ./jstatd.sh
backgrounder : yum install -y java-1.8.0-openjdk-devel
[ OK ] yum java-1.8.0-openjdk-devel
start jstatd.sh
[[email protected] tools]#
如果沒有安裝過jstatd工具,第一次執行腳本 會提示在背景自動安裝java-1.8.0-openjdk-devel
2、檢視jstatd 的程序id
ps -aux | grep jstatd
[[email protected] tools]# ps -aux | grep jstatd
root 20537 0.5 1.1 2987296 43044 ? Ssl 14:55 0:00 jstatd -J-Djava.security.policy=bin/jstatd.all.policy -J-Djava.rmi.server.hostname=xxx.x.xxx.xxx -p1099
root 20557 0.0 0.0 112708 980 pts/0 R+ 14:58 0:00 grep --color=auto jstatd
檢視到jstatd的程序id即 pid的值為 20537
3、通過jstatd的程序id檢視jstatd服務綁定的端口
netstat -nap | grep [pid]
[[email protected] jstatd]# netstat -nap | grep 20537
tcp6 0 0 :::1099 :::* LISTEN 20537/jstatd
tcp6 0 0 :::43381 :::* LISTEN 20537/jstatd
tcp6 0 0 192.168.1.58:1099 27.46.6.154:54788 ESTABLISHED 20537/jstatd
tcp6 0 0 127.0.0.1:1099 127.0.0.1:43212 ESTABLISHED 20537/jstatd
tcp6 0 1 192.168.1.58:51700 xxx.x.xxx.xxx:43381 SYN_SENT 20537/jstatd
tcp6 0 0 127.0.0.1:43212 127.0.0.1:1099 ESTABLISHED 20537/jstatd
unix 2 [ ] STREAM CONNECTED 29306374 20537/jstatd
注意: 前面2個監聽端口,1099 是jstatd預設對外連接配接端口,第二個端口是每次啟動jstatd 服務随機注冊的端口(為什麼随機,可能是出于安全考慮),這個2個tcp端口都需要開放端口權限,如果開了防火牆,需要在防火牆中開放這2端口個tcp權限,如果是雲伺服器,一般都會有安全組,需要在安全組中開放這2個端口的tcp權限,否則jstatd 遠端無法連接配接!
前面2個監聽端口下面出現的一些ESTABLISHED 連接配接資訊 是jstatd 連接配接本機系統上所有jvm應用擷取監控資料的資訊,過一段時間後(幾十秒吧,由本機上運作的java應用數決定),再次執行 netstat -nap | grep [pid] 會發現這些連接配接資訊沒有了,如下:
[[email protected] jstatd]# netstat -nap | grep 20537
tcp6 0 0 :::1099 :::* LISTEN 20537/jstatd
tcp6 0 0 :::43381 :::* LISTEN 20537/jstatd
unix 2 [ ] STREAM CONNECTED 29306374 20537/jstatd
[[email protected] jstatd]#
這表示jstatd 服務啟動準備好了
打開 jvisualvm 監控工具
本地windows打開 安裝jdk時自帶的監控工具 jvisualvm (在jdk安裝目錄下的bin下面去找 jvisualvm.exe)
jvisualvm 檔案 -> 添加遠端主機
右鍵 遠端主機 -> 添加 jstatd 連接配接
就能看到 遠端主機下面一列的jvm應用 點選其中想要監控的應用,右側就可以看到jstatd監控資訊了。
如果右側 沒有Visual GC 工具欄的話,需要手動添加 Visual GC插件,看下我寫的這篇文章: jvisualvm 離線下載下傳安裝插件
jststd監控jvm應用記憶體分析問題 非常有用(可以分析jvm應用的新生代、老年代、永久代記憶體使用,分析如何優化記憶體參數,如:-XX:NewRatio),但是jmx監控資訊有一些jststd 監控資訊裡面并沒有的 ,我們可以在jvisualvm 連接配接 jvm應用 jmx監控,jvisualvm怎麼連接配接jmx 可以看下我的這篇文章: 在本地windows用jConsole jmc jvisualvm監控圖形用戶端 連接配接遠端伺服器java程式jmx監控服務。解決jmx無法連接配接問題
關閉jstatd 服務
./jstatd.sh stop
[[email protected] tools]# ./jstatd.sh stop
stop jstatd.sh.[ OK ]
最後
再次強調一些 需要注意的地方,一個地方出錯可能就會導緻最後連接配接不上,到處找不到原因。
jstatd.sh 腳本裡面 xxx.x.xx.xxx 替換你們自己的伺服器外網ip位址
啟動 jstatd 和 jmx 服務 除了能指定的固定端口外 還會随機生成綁定端口,這些随機生成的綁定端口,如何找到 在上面有介紹,需要開放随機綁定的端口權限,否則就會連不上,并且沒什麼明顯的提示。