工具所在位置:windows下jdk安装路径内,如 C:\Program Files\Java\jdk1.8.0_20\bin\ jvisualvm.exe
双击执行;
效果图如下: 可以看到我本机有一个tomcat运行的监控
VisualVM可以根据需要安装不同的插件,每个插件的关注点都不同,有的主要监控GC,有的主要监控内存,有的监控线程等。
如何安装插件:
1、从主菜单中选择“工具”>“插件”。
2、在“可用插件”标签中,选中该插件的“安装”复选框。单击“安装”。
3、逐步完成插件安装程序。
如果可选插件没有,那么需要更换插件更新地址: 在如下网址中找到自己jdk版本的插件地址:
https://visualvm.github.io/pluginscenters.html
我的的jdk是jdk1.8.0_20则选择如下框中的版本地址,复制;在VisualVM->工具->插件->设置->编辑中替换URL
(此处url历史值能看出安装插件要选什么版本)
点击设置->编辑,粘贴新的url确定,即可看到可用插件会出现,然后选择需要的进行安装;
监控远程
右键远程->添加主机:输入ip地址,右键再选择添加JMX连接
, 填入JMX端口(不知道端口号先随便填,看后面讲解)确定,出现如下错误: 由于JMX没配置或地址不对
(1)首先要修改远程服务器JDK中JMX服务的配置文件,以获得相应的权限:
进入$JAVA_HOME所在的根目录的/jre/lib/management子目录下,
a. 将jmxremote.password.template文件复制为jmxremote.password :
cp -r jmxremote.password.template jmxremote.password
b. 调整jmxremote.access和jmxremote.password的权限为只读写,可以使用如下命令:
chmod 600 jmxremote.access jmxremote.password
c. 打开jmxremote.password文件,去掉这两行前面的注释符号
# monitorRole QED
# controlRole R&D
若要配置账号密码:
打开jmxremote.password,修改,添加用户或密码,建议不要使用默认的用户名和密码登录:
monitorRole 222
jmxuser 111111
newuser 222222
打开jmxremote.access,修改新加/修改的用户权限:
monitorRole readonly
jmxuser readwrite \
create javax.management.monitor.*,javax.management.timer.* \
unregister
newuser readwrite \
create javax.management.monitor.*,javax.management.timer.* \
unregister
JVM的启动配置中添加信息: 此处是tomcat启动,在tomcat启动文件bin/catalina.sh ,添加如下配置(防火墙自行开放端口
):
JAVA_OPTS="-Dcom.sun.management.jmxremote.port=18088
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Djava.rmi.server.hostname=172.19.16.2"
这几个配置的说明如下:
-Dcom.sun.management.jmxremote.port:这个是配置远程connection的jmx端口号
的(默认是1099),
要确定这个端口没有被占用
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false:这两个是固定配置,是JMX的远程服务权限的
-Djava.rmi.server.hostname:这个是配置server的IP的,要使用server的IP最好在机器上先用hostname -i看一下IP
是不是机器本身的IP,如果是127.0.0.1的话要改一下,否则远程的时候连不上。
完了之后,再重复之前添加JMX连接
, 应该就ok了;
Visual GC
远程监控时 点击Visual GC 会提示不受此JVM支持
, 需要使用Jstatd服务来解决
在jdk安装目录下 ,创建一个新的权限文件jstatd.all.policy:
cd /usr/local/src/jdk1.8.0_131/bin/
vim jstatd.all.policy
输入下文 (此处${java.home}
是jre路径,而不是jdk环境变量的$JAVA_HOME
) :
grant codebase "file:${java.home}/../lib/tools.jar" {
permission java.security.AllPermission;
};
然后在 $JAVA_HOME/bin 下执行启动jstatd命令 :
./jstatd -J-Djava.security.policy=jstatd.all.policy
-J-Djava.rmi.server.hostname=172.19.16.2
-p 28088
-J-Djava.rmi.server.logCalls=true &
参数说明:
-J-Djava.security.policy=jstatd.all.policy =号后面的是文件的绝对路径;
-J-Djava.rmi.server.logCalls=true 打开日志,如果客户端有连接过来的请求,可以监控到,便于排错;
-J-Djava.rmi.server.hostname=172.19.16.2 指明本机 hostname 对应的本机地址,
确保该地址可以给客户机访问。因为有的服务器 hostname 对应的 ip 不一定是外网能连上的,最好在这里直接明确指定;
-p 28088 指定服务的端口号,默认是1099,是可选参数。由于以上JMX占用了端口,此处换一个(注意开放端口
)。
完了在visualvm添加jstatd连接
,断后改成上面配置的 28088 ,然后确定,
visualvm会出现运行JVM的容器如tomcat,点击Visual GC即可:
如图:
上图堆内存良好,下图就内存占满,需要分析了
抽样器或Profiler(分析器)
通过抽样器
分析具体哪个对象占用过多使内存占满,可以通过堆dump,分析堆转储分析数量多的对象
或两次堆dump文件对象的增长量,推断泄漏的位置
分析单独一个堆Dump中对象数量很多的情况;
点击某个占用很多空间的类,右键
在实例视图中显示.
;
此处写个内存溢出的类MapTest,Memory,StactQueue用来测试;MapTest中main方法调用Memory的静态方法mm(),mm中循环将StactQueue对象存入一个map,最大Integer.MAX_VALUE次,注意main方法中让线程等待一段时间,以方便打开VisualVM分析
可以大概定位是某个map出现问题;那如何定位是哪个类呢?
如下排名靠前的需要分析的可能性更高 (文件越大,此查找过程CPU计算越卡顿)
生成两次时间间隔的 堆Dump
文件,比如16:03:08一次,16:03:24一次(不要太长,文件太大不便计算分析),
两者之间比较对象增量,剧增可能就有问题
两个堆转储比较: