Skip to main content

JVM实战-JVM性能分析以及调优分析

finen...About 11 minJVMJVM

1 JVM实战篇

1.1 JVM参数

1.1.1 标准参数

-version
-help
-server
-cp

1.1.2 -X参数

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

1.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.1.4 其他参数

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

1.1.5 查看参数

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

1.1.6 设置参数的方式

  • 开发工具中设置比如IDEA,eclipse

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

  • web容器比如tomcat,可以在脚本中的进行设置

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

1.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.1.8 常用参数含义

JVM参数说明:JVM参数open in new window

  • 调优堆栈内存-堆栈大小典型配置参数
配置参数说明示例
-Xmx设置最大堆大小。-Xmx3550m,设置JVM最大可用内存为3550 MB。
-Xms设置JVM初始内存。-Xms3550m,设置JVM初始内存为3550 MB。此值建议与-Xmx相同,避免每次垃圾回收完成后JVM重新分配内存。
-Xmn设置年轻代大小。-Xmn2g,设置年轻代大小为2 GB。整个JVM内存大小=年轻代大小+年老代大小+持久代大小。持久代一般固定大小为64 MB,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
-Xss设置线程的栈大小。-Xss128k,设置每个线程的栈大小为128 KB。说明 JDK 5.0版本以后每个线程栈大小为1 MB,JDK 5.0以前版本每个线程栈大小为256 KB。请依据应用的线程所需内存大小进行调整。在相同物理内存下,减小该值可以生成更多的线程。但是操作系统对一个进程内的线程个数有一定的限制,无法无限生成,一般在3000个~5000个。
-XX:NewRatio=n设置年轻代和年老代的比值。-XX:NewRatio=4,设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。如果设置为4,那么年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5。
-XX:SurvivorRatio=n年轻代中Eden区与两个Survivor区的比值。-XX:SurvivorRatio=4,设置年轻代中Eden区与Survivor区的大小比值。如果设置为4,那么两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6。
-XX:MaxPermSize=n设置持久代大小。-XX:MaxPermSize=16m,设置持久代大小为16 MB。
-XX:MaxTenuringThreshold=n设置垃圾最大年龄。-XX:MaxTenuringThreshold=0,设置垃圾最大年龄。如果设置为0,那么年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,提高了效率。如果将此值设置为较大值,那么年轻代对象会在Survivor区进行多次复制,增加了对象在年轻代的存活时间,增加在年轻代即被回收的概率。
  • 调优回收器GC-吞吐量优先的GC典型配置参数
配置参数说明示例
-XX:+UseParallelGC选择垃圾收集器为并行收集器。-Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20-XX:+UseParallelGC此配置仅对年轻代有效,即在示例配置下,年轻代使用并发收集,而年老代仍旧使用串行收集。
-XX:ParallelGCThreads配置并行收集器的线程数,即同时多少个线程一起进行垃圾回收。说明 此值建议配置与处理器数目相等。-Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20-XX:ParallelGCThreads=20表示配置并行收集器的线程数为20个。
-XX:+UseParallelOldGC配置年老代垃圾收集方式为并行收集。说明 JDK 6.0支持对年老代并行收集。-Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC-XX:+UseParallelOldGC表示对年老代进行并行收集。
-XX:MaxGCPauseMillis设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值。-Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100-XX:MaxGCPauseMillis=100设置每次年轻代垃圾回收的最长时间为100 ms。
-XX:+UseAdaptiveSizePolicy设置此选项后,并行收集器自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低响应时该间或者收集频率,该值建议使用并行收集器时,并且一直打开。-Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100 -XX:+UseAda
  • 响应时间优先的GC典型配置参数
配置参数说明示例
-XX:+UseConcMarkSweepGC设置年老代为并发收集。说明 配置了-XX:+UseConcMarkSweepGC,建议年轻代大小使用-Xmn设置。-Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
-XX:+UseParNewGC设置年轻代为并行收集。可与CMS收集同时使用。JDK 5.0以上版本,JVM根据系统配置自行设置,无需再设置此值。-Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
-XX:CMSFullGCsBeforeCompaction由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理。-Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection-XX:CMSFullGCsBeforeCompaction=5,表示运行GC5次后对内存空间进行压缩、整理。
-XX:+UseCMSCompactAtFullCollection打开对年老代的压缩。说明 该值可能会影响性能,但是可以消除碎片。-Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection
  • 用于辅助的GC典型配置参数
配置参数说明
-XX:+PrintGC用于输出GC日志。
-XX:+PrintGCDetails用于输出GC日志。
-XX:+PrintGCTimeStamps用于输出GC时间戳(JVM启动到当前日期的总时长的时间戳形式)。示例如下:0.855: [GC (Allocation Failure) [PSYoungGen: 33280K->5118K(38400K)] 33280K->5663K(125952K), 0.0067629 secs] [Times: user=0.01 sys=0.01, real=0.00 secs]
-XX:+PrintGCDateStamps用于输出GC时间戳(日期形式)。示例如下:2022-01-27T16:22:20.885+0800: 0.299: [GC pause (G1 Evacuation Pause) (young), 0.0036685 secs]
-XX:+PrintHeapAtGC在进行GC前后打印出堆的信息。
-Xloggc:../logs/gc.log日志文件的输出路径。

全部参数查看:https://www.oracle.com/java/technologies/javase/vmoptions-jsp.htmlopen in new window
image-20220309162923416

1.2 常用命令

1.2.1 jps

查看java进程

1.2.2 jinfo

(1)实时查看和调整JVM配置参数

(2)查看

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

(3)修改

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

jinfo -flag [+|-] PID

jinfo -flag = PID

(4)查看曾经赋过值的一些参数

jinfo -flags PID

1.2.3 jstat

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

(2)查看类装载信息

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

(3)查看垃圾收集信息

jstat -gc PID 1000 10
image-20220310220241447
image-20220310220241447

1.2.4 jstack

(1)查看线程堆栈信息

(2)用法

jstack PID

(3) 排查死锁

  • DeadLockDemo
//运行主类
public class DeadLockDemo
{
    public static void main(String[] args)
    {
        DeadLock d1=new DeadLock(true);
        DeadLock d2=new DeadLock(false);
        Thread t1=new Thread(d1);
        Thread t2=new Thread(d2);
        t1.start();
        t2.start();
    }
}
//定义锁对象
class MyLock{
    public static Object obj1=new Object();
    public static Object obj2=new Object();
}
//死锁代码
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()+"----if获得obj1锁");
                    synchronized(MyLock.obj2) {
                        System.out.println(Thread.currentThread().getName()+"----if获得obj2锁");
                    }
                }
            }
        }
        else {
            while(true){
                synchronized(MyLock.obj2) {
                    System.out.println(Thread.currentThread().getName()+"----否则获得obj2锁");
                    synchronized(MyLock.obj1) {
                        System.out.println(Thread.currentThread().getName()+"----否则获得obj1锁");

                    }
                }
            }
        }
    }
}
  • jstack 分析
image-20220310221042830
image-20220310221042830

1.2.5 jmap

(1)生成堆转储快照

(2)打印出堆内存相关信息

1.设置:-XX:+PrintFlagsFinal -Xms300M -Xmx300M
2.查看jmap -heap PID
image-20220310221505262
image-20220310221505262
image-20220310221521362
image-20220310221521362

(3)dump出堆内存相关信息、

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

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

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

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hprof
设置堆内存大小: -Xms20M -Xmx20M
启动,然后访问localhost:9090/heap,使得堆内存溢出

(5)关于dump下来的文件

一般dump下来的文件可以结合工具来分析

1.3 常用工具

1.3.1 jconsole

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

启动命令:jconsole

1.3.2 jvisualvm

启动命令:jvisualvm

1.3.2.1 监控本地Java进程

image-20220310222954259
image-20220310222954259

1.3.2.2 监控远端Java进程

比如监控远端tomcat,演示部署在阿里云服务器上的tomcat

(1)在visualvm中选中“远程”,右击“添加”

(2)主机名上写服务器的ip地址,比如31.100.39.63,然后点击“确定”

(3)右击该主机“31.100.39.63”,添加“JMX”[也就是通过JMX技术具体监控远端服务器哪个Java进程]

(4)要想让服务器上的tomcat被连接,需要改一下 bin/catalina.sh 这个文件

JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote -
Djava.rmi.server.hostname=31.100.39.63 -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.26.225.240 172.17.0.1
vim /etc/hosts
172.26.255.240 31.100.39.63

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

(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

1.3.3 Arthas

github :https://github.com/alibaba/arthasopen in new window

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

1.3.3.1 下载安装

curl -O https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar
# 然后可以选择一个Java进程

Print usage

java -jar arthas-boot.jar -h

1.3.3.2 常用命令

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:输出当前方法被调用的调用路径

1.3.4 MAT

Java堆分析器,用于查找内存泄漏
Heap Dump,称为堆转储文件,是Java进程在某个时间内的快照
下载地址 :https://www.eclipse.org/mat/downloads.phpopen in new window

1.3.4.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

1.3.4.2 获取Dump文件

  • 手动
jmap -dump:format=b,file=heap.hprof 44808
  • 自动
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hprof

1.3.4.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

Top Consumers

1.3.5 GC日志分析工具

-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps
-Xloggc:gc.log
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.8