JVM虚拟机监控及性能调优实战

目录

jvisualvm介绍

复制代码
1. jvisualvm是JDK自带的可以远程监控内存,跟踪垃圾回收,执行时内存,CPU/线程分析,生成堆快照等的工具。
2. jvisualvm是从JDK1.6开始被继承到JDK中的。

jvisualvm使用

jvisualvm监控远程服务器

开启远程监控

  • 通过在服务器上设置jmx参数来开启

    复制代码
    vi /etc/profile
    export JAVA_OPTS='-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=N -Djava.rmi.server.hostname=x.x.x.x -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false'
  • 通过启动jar命令开启

    复制代码
    java -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=N -Djava.rmi.server.hostname=x.x.x.x -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -jar xxx.jar

连接

  • 打开jvisualvm,在远程中添加需要监控的服务器,然后再在该服务器下添加jmx监控连接

jvisualvm集成Visual-GC插件

Visual GC插件安装

  • 更改visual-gc配置中心URL
  • 安装Visual GC Plugin

Visual GC正确开启步骤

  • 在远程主机上添加安全策略文件

    复制代码
    [root@localhost ~] touch jstatd.all.policy
    [root@localhost ~] vi jstatd.all.policy
    grant codebase "file:${java.home}/../lib/tools.jar" {
        permission java.security.AllPermission;
    };

    注意:如果没有配置JDK环境变量,file后需要添加tool.jar的绝对路径

  • 在远程主机上启动监控

    复制代码
    [root@localhost ~] jstatd -J-Djava.security.policy=/xxx/jstatd.all.policy  -J-Djava.rmi.server.logCalls=true -J-Djava.rmi.server.hostname=xx.xx.xx.xx -p 1099
    • 参数说明
      • -J-Djava.rmi.server.logCalls=true 打开日志,便于排错
      • -J-Djava.rmi.server.hostname=xx.xx.xx.xx hostname是本机IP地址,确保client能访问到,另外查看本机的hosts是否有其他配置,这里有坑,具体参照常见问题中的 XXXX
  • 可以查看端口是否被正常监听

    复制代码
    [root@localhost ~]# lsof -i:1099
    COMMAND    PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
    jstatd  110703 root   15u  IPv6 7374636      0t0  TCP *:rmiregistry (LISTEN)
    jstatd  110703 root   17u  IPv6 7373817      0t0  TCP localhost:rmiregistry->x.x.x.x:62209 (ESTABLISHED)
  • 使用visualvm连接

    • 添加jstatd连接,注意端口号和远程服务器开启的端口号保持一致

    注意:远程服务器端口要设置开放

  • 参考视图

常见问题

  • 开启OOM-dump

    复制代码
    nohup java -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=N -Djava.rmi.server.hostname=x.x.x.x -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -XX:+HeapDumpOnOutOfMemoryError -jar xxx.jar -XX:HeapDumpPath=~/dumps/ > nohup.log 2>&1 &
  • Visual GC提示"不受此JVM支持"

    复制代码
    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:884)
        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)
  • Could not contact registry,指向的IP地址是一个其他的地址

    复制代码
    [root@localdomain bin]# ./jstatd -J-Djava.security.policy=jstatd.all.policy
    Could not contact registry
    Connection refused to host: y.y.y.y; nested exception is:
            java.net.ConnectException: Connection refused
    java.rmi.ConnectException: Connection refused to host: y.y.y.y; nested exception is:

    注意:我在这里查看了远程机器的hosts,发现其配有一些其他的IP,将其删除后能够联通

  • 快速定位导致cpu飙升的线程堆栈信息

    复制代码
    top 首先通过top命令找到高负载的CPU,获取进程id
    top -p <进程id> 精确定位到cpu高的进程,然后按H键,查看该进程所有线程
        或者 top -p 进程id -H 查看进程下的线程
    printf "%x" 进程id 将进程号转化为16进制,注意把十六进制的大写字母转换为小写
    jstack 进程id > xxx.txt 导出日志,然后在日志中查找nid=转换后进程id
        或者 jstack 进程ID|grep -A 10 55a0   10表示这个线程所在行后面10行,55a0是进程ID转换后的十六进制
  • 查看堆内存使用情况

    复制代码
    jps查看各个应用进程id
    jmap -heap java项目进程id
    jmap -histo 进程id > log.txt 查看此应用中各实例生成情况
    jmap -histo:live [pid] > log.txt 过滤存活的对象
  • 查找代码死锁

    复制代码
    jstack 进程id > xxx.txt 导出日志
    搜索 deadlock 或者查 locked关键字找到发生死锁线程

引用

本文由mdnice多平台发布

相关推荐
devlei1 小时前
从源码泄露看AI Agent未来:深度对比Claude Code原生实现与OpenClaw开源方案
android·前端·后端
努力的小郑3 小时前
Canal 不难,难的是用好:从接入到治理
后端·mysql·性能优化
Victor3564 小时前
MongoDB(87)如何使用GridFS?
后端
Victor3564 小时前
MongoDB(88)如何进行数据迁移?
后端
小红的布丁4 小时前
单线程 Redis 的高性能之道
redis·后端
GetcharZp4 小时前
Go 语言只能写后端?这款 2D 游戏引擎刷新你的认知!
后端
宁瑶琴5 小时前
COBOL语言的云计算
开发语言·后端·golang
普通网友6 小时前
阿里云国际版服务器,真的是学生党的性价比之选吗?
后端·python·阿里云·flask·云计算
IT_陈寒7 小时前
Vue的这个响应式问题,坑了我整整两小时
前端·人工智能·后端
Soofjan7 小时前
Go 内存回收-GC 源码1-触发与阶段
后端