如何优雅的学习JVM,实战篇(四)

时间:2020-05-30
本文章向大家介绍如何优雅的学习JVM,实战篇(四),主要包括如何优雅的学习JVM,实战篇(四)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

# 一、JVM参数

## 1.1 标准参数

-version  
-help  
-server  
-cp  

## 1.2 -X参数

非标准参数,也就是在JDK各个版本中可能会变动

-Xint   解释执行  
-Xcomp  第一次使用就编译成本地代码  
-Xmixed  混合模式,JVM自己来决定  

## 1.3 -XX参数

使用得最多的参数类型,非标准化参数,相对不稳定,主要用于JVM调优和Debug

a.Boolean类型  
格式:-XX:\[+-\]<name>      +或-表示启用或者禁用name属性  
比如:-XX:+UseConcMarkSweepGC  表示启用CMS类型的垃圾回收器  
-XX:+UseG1GC       表示启用G1类型的垃圾回收器  
b.非Boolean类型  
格式:-XX<name>=<value> 表示name属性的值是value  
比如:-XX:MaxGCPauseMillis=500  

## 1.4 其它参数

-Xms1000等价于 -XX:InitialHeapSize=1000  
-Xmx1000等价于 -XX:MaxHeapSize=1000  
-Xss1000等价于 -XX:ThreadStackSize=1000  

这一块内容也相当于-XX类型的参数

## 1.5 查看参数

java -XX:+PrintFlagsFinal -version > flags.txt

上图值得注意的是“=”表示默认值,“:=”表示被用户或JVM修改后的值

一般需要设置参数,可以先查下当前参数是什么,然后再进行修改

## 1.6 设置参数的方式

* 开发工具中进行设置IDEA、eclipse

* 运行jar包的时候:java -XX:+UseG1GC xxx.jar

* Web容器比如Tomcat,可以在脚本中进行设置

* 通过**jinfo**命令实时调整某个java进程的参数(参数只有被标记位**manageable**的flags可以被实时修改)

# 1.7 单位换算和实践

1Byte(字节)=8bit(位)  
1KB=1024Byte(字节)  
1MB=1024KB  
1GB=1024MB  
1TB=1024GB  

1、设置堆内存大小和参数打印

-Xmx100M -Xms100M -XX:+PrintFlagsFinal

2、查询+PrintFlagsFinal

:=true

3、查询堆内存大小MaxHeapSize

:= 104857600

4、换算

104857600(Byte)/1024=102400(KB)  
102400(KB)/1024=100(MB)  

5、结论

`104857600是字节单位`

# 1.8 常用参数的含义

# 二、常用命令

## 2.1 jps

查看java进程 

## 2.2 jinfo

1、实时查看

`jinfo -flag name PID 查看某个java进程的name属性的值`

jinfo -flag MaxHeapSize PID  
jinfo -flag UseG1GC PID  

2、调整JVM配置参数

参数只有被标记为manageable的flags可以被实时修改

jinfo -flag \[+|-\] PID  
jinfo -flag = PID  

3、查看曾经赋过值的一些参数

`jinfo -flags PID`

## 2.3 jstat

1、查看虚拟机性能统计信息

2、查看java进程的类装载信息

jstat -class PID 1000 10   查看某个java进程的类装载信息,每1000毫秒输出一次,共输出10 次

3、查看垃圾收集信息

`jstat -gc PID 1000 10`

## 2.4 jstack

1、查看线程堆栈信息

`jstack PID`

2、排查死锁的案例

示例代码:

public class DeadLockDemo {

    public static void main(String\[\] args) {  
        DeadLock deadLock1 = new DeadLock(true);  
        DeadLock deadLock2 = new DeadLock(false);  
        Thread thread1 = new Thread(deadLock1);  
        Thread thread2 = new Thread(deadLock2);  
        thread1.start();  
        thread2.start();  
    }

    static class MyLock {  
        public static Object obj1 = new Object();  
        public static Object obj2 = new Object();  
    }

    static class DeadLock implements Runnable {  
        private boolean flag;

        DeadLock(boolean flag) {  
            this.flag = flag;  
        }

        public void run() {  
            if(flag) {  
                while (true) {  
                    synchronized (MyLock.obj1) {  
                        System.out.println(Thread.currentThread().getName() + "如果获得obj1的锁");  
                        synchronized (MyLock.obj2) {  
                            System.out.println(Thread.currentThread().getName() + "如果获得obj2的锁");  
                        }  
                    }  
                }  
            }else {  
                while (true) {  
                    synchronized (MyLock.obj2) {  
                        System.out.println(Thread.currentThread().getName() + "否则获得obj2的锁");  
                        synchronized (MyLock.obj1) {  
                            System.out.println(Thread.currentThread().getName() + "否则获得obj1的锁");  
                        }  
                    }  
                }  
            }  
        }  
    }  
}  

运行main方法的结果

**jstack分析**

把打印信息拉到最后可以发现

## 2.5 jmap

1、生成堆转存储快照

2、打印出堆内存相关信息

-XX:+PrintFlagsFinal -Xms300M -Xmx300M  
jmap -heap PID  

3、dump堆内存相关信息

jmap -dump:format=b,file=heap.hprof PID  
jmap -dump:format=b,file=heap.hprof 44808  

4、要是能在发生堆内存溢出的时候,能自动dump出该文件就好了

一般在开发过程中,JVM参数可以加上下面两句,这样在程序内存溢出的时候,会自动dump该文件

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hprof

# 三、常用工具

## 3.1 jconsole

JConsole工具是JDK自带的可视化监控工具。查看java应用程序的运行概况、监控堆信息、永久区使用
情况、类加载情况等。

命令行中输入:jconsole

## 3.2 jvisualvm

**1、可以监控本地的java进程的CPU,类,线程等**

**2、可以监控远端tomcat,演示部署在阿里云服务器上的tomcat**

(1)在visualvm中选中“远程”,右击“添加”
(2)主机名上写服务器的ip地址,比如39.105.32.236,然后点击“确定”
(3)右击该主机“39.105.32.236”,添加“JMX”[也就是通过JMX技术具体监控远端服务器哪个Java进程]
(4)要想让服务器上的tomcat被连接,需要改一下 bin/catalina.sh 这个文件

注意下面的8998不要和服务器上其他端口冲突

JAVA\_OPTS="$JAVA\_OPTS -Dcom.sun.management.jmxremote -Djava.rmi.server.hostname=39.105.32.236 -Dcom.sun.management.jmxremote.port=8998 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access -Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password"  

(5)在 ../conf 文件中添加两个文件jmxremote.access和jmxremote.password

**jmxremote.access 文件**

guest readonly  
manager readwrite  

**jmxremote.password 文件**

guest guest  
manager manager  

授予权限 : chmod 600 *jmxremot*

(6)将连接服务器地址改为公网ip地址

hostname -i  查看输出情况
172.17.6.246 172.17.0.1
vim /etc/hosts
172.17.6.246 339.105.32.236

(7)设置上述端口对应的阿里云安全策略和防火墙策略

firewall-cmd --add-port=8080/tcp --permanent  
firewall-cmd --add-port=8998/tcp --permanent  
systemctl restart firewalld  

(8)启动tomcat,来到bin目录

./startup.sh

(9)查看tomcat启动日志以及端口监听

tail -f ../logs/catalina.out  
lsof -i tcp:8080  

(10)查看8998监听情况,可以发现多开了几个端口

lsof -i:8998  得到PID  
netstat -antup | grep PID  

(11)在刚才的JMX中输入8998端口,并且输入用户名和密码则登录成功

端口:8998  
用户名:manager  
密码:manager  

## 3.3 阿里的Arthas

Arthas是阿里巴巴开源的Java诊断工具,采用命令行交互模式,是排查jvm相关问题的利器。

**github:** https://github.com/alibaba/arthas

下载arthas-boot.jar,然后用java -jar的方式启动:

curl -O https://alibaba.github.io/arthas/arthas-boot.jar  
java -jar arthas-boot.jar  

打印帮助信息:

`java -jar arthas-boot.jar -h`

常用命令

具体每个命令怎么使用,大家可以自己查阅资料!

version:查看arthas版本号  
help:查看命名帮助信息  
cls:清空屏幕  
session:查看当前会话信息  
quit:退出arthas客户端  
\-\-\-  
dashboard:当前进程的实时数据面板  
thread:当前JVM的线程堆栈信息  
jvm:查看当前JVM的信息  
sysprop:查看JVM的系统属性  
\-\-\-  
sc:查看JVM已经加载的类信息  
dump:dump已经加载类的byte code到特定目录  
jad:反编译指定已加载类的源码  
\-\-\-  
monitor:方法执行监控  
watch:方法执行数据观测  
trace:方法内部调用路径,并输出方法路径上的每个节点上耗时  
stack:输出当前方法被调用的调用路径  
......  

## 3.4 MAT

Java堆分析器,用于查找内存泄漏

Heap Dump,称为堆转储文件,是Java进程在某个时间内的快照

**下载地址:** https://www.eclipse.org/mat/downloads.php

1、Dump信息包含的内容

* All Objects

Class, fields, primitive values and references

* All Classes

Classloader, name, super class, static fields

* Garbage Collection Roots

Objects defined to be reachable by the JVM

* Thread Stacks and Local Variables

The call-stacks of threads at the moment of the snapshot, and per-frame information about local
objects

2、获取Dump文件

* 手动

`jmap -dump:format=b,file=heap.hprof 44808`

自动

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hprof

3、使用

* Histogram

Histogram可以列出内存中的对象,对象的个数及其大小

Class Name:类名称,java类名  
Objects:类的对象的数量,这个对象被创建了多少个  
Shallow Heap:一个对象内存的消耗大小,不包含对其他对象的引用  
Retained Heap:是shallow Heap的总和,即该对象被GC之后所能回收到内存的总和  

右击类名--->List Objects--->with incoming references--->列出该类的实例

右击Java对象名--->Merge Shortest Paths to GC Roots--->exclude all ...--->找到GC Root以及原因

* Leak Suspects

查找并分析内存泄漏的可能原因

`Reports--->Leak Suspects--->Details`

* Top Consumers

列出大对象

## 3.5 GC日志分析工具

要想分析日志的信息,得先拿到GC日志文件才行,所以得先配置一下

根据前面参数的学习,下面的配置很容易看懂

-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps  
-Xloggc:gc.log  

* 在线工具

https://gceasy.io/

* GCViewer

 

$flag 上一页 下一页