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

一、JVM参数

1.1 标准参数

1
2
3
4
-version
-help
-server
-cp

1.2 -X参数

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

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

1.3 -XX参数

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

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

1.4 其它参数

1
2
3
-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 单位换算和实践

1
2
3
4
5
1Byte(字节)=8bit(位)
1KB=1024Byte(字节)
1MB=1024KB
1GB=1024MB
1TB=1024GB

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

-Xmx100M -Xms100M -XX:+PrintFlagsFinal

2、查询+PrintFlagsFinal

:=true

3、查询堆内存大小MaxHeapSize

:= 104857600

4、换算

1
2
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属性的值

1
2
jinfo -flag MaxHeapSize PID
jinfo -flag UseG1GC PID

2、调整JVM配置参数

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

1
2
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、排查死锁的案例

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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、打印出堆内存相关信息

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

3、dump堆内存相关信息

1
2
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不要和服务器上其他端口冲突

1
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 文件

1
2
guest readonly
manager readwrite

jmxremote.password 文件

1
2
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)设置上述端口对应的阿里云安全策略和防火墙策略

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

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

./startup.sh

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

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

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

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

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

1
2
3
端口:8998
用户名:manager
密码:manager

3.3 阿里的Arthas

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

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

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

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

打印帮助信息:

java -jar arthas-boot.jar -h

常用命令

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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可以列出内存中的对象,对象的个数及其大小

1
2
3
4
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日志文件才行,所以得先配置一下

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

1
2
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps
-Xloggc:gc.log
  • 在线工具

https://gceasy.io/

  • GCViewer