jvisualvm分析java应用内存需要远程服务上启动jstatd服务(jmx也有内存监控信息,不过没有jstatd内存信息详细),网上各种相关文章大部分都是介绍的简单模糊,很多要注意的地方没介绍,真正按着操作的话,各种连不上没反应,让人着急!
下面分享个我在项目中分析内存时服务器上启动jstatd服务的脚本工具,自动安装jstatd环境,能够快速启动关闭jstatd服务。一些需要注意和容易出错的地方我也会下面指出。
我在服务器上安装的是openjdk1.8 ,所以jstatd.sh 脚本里面自动安装的jstatd工具也是1.8的,如果是别的版本自己看着改下。
下面进入正题
创建jstatd 脚本
jstatd脚本有2个文件: 启动脚本文件 jstatd.sh 和 权限配置文件 jstatd.all.policy
[root@hw-biz-alpha 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
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
[root@hw-biz-alpha tools]# ./jstatd.sh
backgrounder : yum install -y java-1.8.0-openjdk-devel
[ OK ] yum java-1.8.0-openjdk-devel
start jstatd.sh
[root@hw-biz-alpha tools]#
如果没有安装过jstatd工具,第一次执行脚本 会提示在后台自动安装java-1.8.0-openjdk-devel
2、查看jstatd 的进程id
ps -aux | grep jstatd
[root@hw-biz-alpha 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]
[root@hw-biz-alpha 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] 会发现这些连接信息没有了,如下:
[root@hw-biz-alpha 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
[root@hw-biz-alpha 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
[root@hw-biz-alpha tools]# ./jstatd.sh stop
stop jstatd.sh.[ OK ]
最后
再次强调一些 需要注意的地方,一个地方出错可能就会导致最后连接不上,到处找不到原因。
jstatd.sh 脚本里面 xxx.x.xx.xxx 替换你们自己的服务器外网ip地址
启动 jstatd 和 jmx 服务 除了能指定的固定端口外 还会随机生成绑定端口,这些随机生成的绑定端口,如何找到 在上面有介绍,需要开放随机绑定的端口权限,否则就会连不上,并且没什么明显的提示。