jvisualvm
是JDK自带的具有图形界面操作功能的JVM
性能监控和诊断工具,它不仅能分析和诊断堆转储文件,在线实时监控本地JVM
进程,还能监控远程服务器上的JVM
进程。
1 分析服务器下载dump文件
1)在我们在安装JDK的bin目录双击jvisaulvm.exe
程序,程序启动成功后会进入Java VisualVM
界面
2)依次点击 文件-> 装入-> 选择文件名和文件类型,文件类型选择【堆Dump】导入我们从服务器上下载的dump文件
3)然后点击【打开】后 Java VisualVM
UI 的右边主界面会新增一个Tab页显示导入的dump文件的概要信息
4)点击下面的【显示线程】链接可以看到线程信息
5)点击【概要】右边的【类】可以看到主要占内存的类名、实例数以及占内存大小
可以看到这个堆中占内存前三位的分别是byte[]
、String
和 ConcurrentHashMap$Node
三个类
注意:生产环境一般不能使用jmap -dump
命令生成堆转储文件,因为执行这个命令的时候会导致STW
(应用主线程停顿),影响应用的正常使用。而一般通过设置两个jvm
启动参数:-XX:+HeapDumpOnOutOfMemoryError
和 -XX:HeapDumpPath=<filename>
在堆内存溢出时实现自动生成堆转储文件。然后我们从服务器上下载堆转储文件后通过Java VisualVM
或者Eclipse Memory Analyzer
内存分析工具导入我们下载的dump文件进行分析诊断。
2 分析内存溢出dump文件
首先需要我们设置JVM启动参数测试堆内存溢出时自动导出堆转储文件
1)在我们的本地启动的Java服务中通过IDEA
设置启动类参数
四个JVM启动参数分别如下:
-Xms50m
-Xmx50m
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=D:\heapdump\blogDump.hprof
然后点击下面的【ok】使之生效
2)在JVMTestController
类中新增一个能导致内存溢出的接口
@GetMapping("/testOutMemoryError")public RespBean<List<UserDTO>> outMemoryErrorTest(){List<UserDTO> userDTOList = new ArrayList<>();for(int i=0;i<1000000;i++){UserDTO userDTO = new UserDTO();userDTO.setId(i+1);userDTO.setUsername("username"+i);userDTO.setNickname("张三"+i);userDTO.setPhoneNum(18975623568L);userDTO.setEmail("ZhangSan"+i+"@163.com");userDTO.setEnabled(1);userDTO.setRegTime(new Timestamp(System.currentTimeMillis()));userDTO.setUpdateTime(new Timestamp(System.currentTimeMillis()));userDTOList.add(userDTO);}RespBean<List<UserDTO>> respBean = new RespBean<>();respBean.setStatus(200);respBean.setMsg("success");respBean.setData(userDTOList);return respBean;}
3)重启服务后在ApiPost
中新建一个http接口,并在请求头中带上用户登录成功后返回的authToken
认证信息
点击【发送按钮】一段时间后会返回内存溢出异常信息,同时在D:\heapdump
目录下生成了堆转储文件blogDump.hprof
4)我们同样在 Java VisualVM
中导入这个dump
文件可以看到它的概要信息和类实例信息
内存溢出堆转储概要信息
内存溢出堆转储类实例信息
从内存溢出堆转储实例信息中我们可以看到UserDTO
类产生了47899个实例对象占用了4406708字节的堆内存。
3 本地JVM监控
本地监控很简单,打开VisualVM
就可以从左侧栏目里看到本机的应用,点击对应的应用就可以看到对应的内存、线程、GC信息
如果应用出现线程死锁也能通过【线程】tab页看到
点击右上方的【线程 Dump】可以看到线程死锁的具体原因
5 远程JVM监控
VisualVM
不仅能监控本地的应用程序,还可以监控远程服务器上的应用,虽然远程监控一般不会用于生产环境的,但是在测试环境做一些压力测试做一些性能的预调优,这个时候使用VisualVM来远程监控测试服务器的JVM使用情况,这样有助于我们了解到JVM
的实时运行状态而进行优化和调整。
1)应用配置jmx支持
需要使用VisualVM监控某个远程服务器的JVM应用,那么首先要对需要配置远程监控应用对MX的支持
配置方式:
- jar包启动:直接 java -jar <jmx相关参数>;
- tomcat启动:编辑tomcat的
catalina.sh
配置文件增加JAVA_OPTS配置
jar 包启动配置案例:
nohup java -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8999 -Dcom.sun.management.jmxremote.local.only=true -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.rmi.port=8999 -Dcom.sun.management.jmxremote.access.file=jmx.access -Dcom.sun.management.jmxremote.password.file=jmx.password -Djava.rmi.server.hostname=159.138.489 -jar jstx-server.jar&
需要注意的参数:
Dcom.sun.management.jmxremote.port
:指定jms通讯端口,这个随意只要不与其他应用冲突即可Djava.rmi.server.hostname
:连接IP,填写当前服务器的外网IPDcom.sun.management.jmxremote.ssl
:是否位加密连接Dcom.sun.management.jmxremote.authenticate
:是否进行权限连接认证,flase 不需要,ture的话就需要指定用户名,密码配置。management.jmxremote.access.file
: 用户名 和对应用户的权限配置Dcom.sun.management.jmxremote.password.file
:用户名对应的密码- 创建用户名密码
- 如果
Dcom.sun.management.jmxremote.authenticate
配置为true则需要进行此步骤
编辑jmx.access
文件添加用户名 并指定权限
执行命令:vim jmx.access
添加内容:admin readwrite
jmx.password
文件里指定用户名和对应密码
执行命令:vim jmx.access
添加内容:admin 123456
修改password,access文件访问权限:
Chmod –R 600 jmx.passwordChmod –R 600 jmx.access
2)建立内网公网IP映射
如果是云服务器则需要建立局域网与公网IP映射
vim /etc/hosts
3)开放端口访问限制
- 防火墙:
Dcom.sun.management.jmxremote.port
对应端口 - 云服务器安全组策略开放
Dcom.sun.management.jmxremote.port
对应的端口
4)VisualVM进行远程连接
添加远程服务器:
建立JMX
连接:
连接成功:
远程jmx连接成功之后就可以像监视本地JVM
进程一样监视远程服务器上的JVM
进程了。
不过生产环境远程服务器上的JMV
进程指标的监控大多使用阿里开源的Arthas
中间件进行线上JVM
调优。