JVM调优与GC日志

Arthas

Arthas是Alibaba开元的Java诊断工具。采用命令行交互式模式,可以定位和诊断线上程序的问题。

Arthas的使用

  1. 下载
# github下载arthas 
wget https://alibaba.github.io/arthas/arthas‐boot.jar 
# 或者 Gitee 下载 
wget https://arthas.gitee.io/arthas‐boot.jar
  1. 运行
    用java -jar运行即可,可以识别机器上所有Java进程(我们这里之前已经运行了一个Arthas测试程序,代码见下方)
    在这里插入图片描述

测试

  1. 实例代码
package com.jvm.jvm1;

import java.util.HashSet;

public class DeadLockTest {
    private static Object lock1 = new Object();
    private static Object lock2 = new Object();

    public static void main(String[] args) {
        hishCPU();
        deadLock();
        addHashSetThread();
    }

    private static void addHashSetThread() {
        new Thread(()->{
            int count=0;
            HashSet<Object> set=new HashSet<>();
            while (true){
                set.add("count"+count);
                count++;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private static void hishCPU() {
        new Thread(()->{
            while (true){

            }
        }).start();
    }

    private static void deadLock() {
        new Thread(()->{
            synchronized (lock1){
                try {
                    System.out.println("Abegin");
                    Thread.sleep(4000);

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock2){
                    System.out.println("Aend");
                }
            }
        }).start();
        new Thread(()->{
            synchronized (lock2){
                try {
                    System.out.println("Bbegin");
                    Thread.sleep(4000);

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock1){
                    System.out.println("Bend");
                }
            }
        }).start();
    }
}

  1. 选择进程序号1,进入进程信息操作
    在这里插入图片描述
  2. 输入dashboard 查看整个进程的运行情况,线程,内存,GC,运行环境信息;
    在这里插入图片描述
  3. 输入thread可以查看线程详细情况
    在这里插入图片描述
  4. 输入 thread加上线程ID 可以查看线程堆栈
    在这里插入图片描述
  5. 输入 thread -b 可以查看线程死锁
    在这里插入图片描述
  6. 输入 jad加类的全名 可以反编译,这样可以方便我们查看线上代码是否是正确的版本

在这里插入图片描述
8. 使用 ognl 命令可以查看线上系统变量的值,甚至可以修改变量的值
在这里插入图片描述
更多命令使用可以用help命令查看,或查看文档:https://alibaba.github.io/arthas/commands.html#arthas
除了该工具、还有其他的一些、例如jvisualvm,JProfiler等;

GC日志详解

对于java应用我们可以通过一些配置把程序运行过程中的gc日志全部打印出来,然后分析gc日志得到关键性指标,分析 GC原因,调优JVM参数。

‐Xloggc:./gc‐%t.log ‐XX:+PrintGCDetails ‐XX:+PrintGCDateStamps ‐XX:+PrintGCTimeStamps ‐XX:+PrintGCCause ‐XX:+UseGCLogFileRotation ‐XX:NumberOfGCLogFiles=10 ‐XX:GCLogFileSize=100M

Tomcat则直接加在JAVA_OPTS变量里。

分析GC日志

运行程序加上对应gc日志

 java ‐jar ‐Xloggc:./gc‐%t.log ‐XX:+PrintGCDetails ‐XX:+PrintGCDateStamps ‐XX:+PrintGCTimeStamps ‐XX:+PrintGCCause
 ‐XX:+UseGCLogFileRotation ‐XX:NumberOfGCLogFiles=10 ‐XX:GCLogFileSize=100M microservice‐eureka‐server.jar

下图中是我截取的JVM刚启动的一部分GC日志
在这里插入图片描述
第一行红框为项目的配置参数。。这里不仅配置了打印GC日志,还有相关的VM内存参数。
第二行红框中的是在这个GC时间点发生GC之后相关GC情况。

  1. 对于2.909: 这是从jvm启动开始计算到这次GC经过的时间,前面还有具体的发生时间日期
  2. Full GC(Metadata GC Threshold)指这是一次full gc,括号里是gc的原因, PSYoungGen是年轻代的GC, ParOldGen是老年代的GC,Metaspace是元空间的GC
  3. 6160K->0K(141824K),这三个数字分别对应GC之前占用年轻代的大小,GC之后年轻代占用,以及整个年轻代的大 小
  4. 112K->6056K(95744K),这三个数字分别对应GC之前占用老年代的大小,GC之后老年代占用,以及整个老年代的 大小
  5. 6272K->6056K(237568K),这三个数字分别对应GC之前占用堆内存的大小,GC之后堆内存占用,以及整个堆内存 的大小。
  6. 20516K->20516K(1069056K),这三个数字分别对应GC之前占用元空间内存的大小,GC之后元空间内存占用,以 及整个元空间内存的大小
  7. 0.0209707是该时间点GC总耗费时间

截图中、发现好几次Full GC都是由于元空间不够导致的,应该将元空间调大点;

 java ‐jar ‐Xloggc:./gc‐adjust‐%t.log ‐XX:MetaspaceSize=10M ‐XX:MaxMetaspaceSize=10M ‐XX:+PrintGCDetails ‐XX:+Print GCDateStamps ‐XX:+PrintGCTimeStamps ‐XX:+PrintGCCause ‐XX:+UseGCLogFileRotation ‐XX:NumberOfGCLogFiles=10 ‐XX:GCLogFileSize=100M  microservice‐eureka‐server.jar

调整完我们再看下gc日志发现已经没有因为元空间不够导致的fullgc了

对于CMS和G1收集器的日志会有一点不一样,也可以试着打印下对应的gc日志分析下,可以发现gc日志里面的gc步骤跟之前的类似;

package com.jvm.jvm1;



import java.util.ArrayList;
import java.util.List;

public class HeapSize {
    byte[] a = new byte[1024 * 100];

    public static void main(String[] args) throws InterruptedException {
        List<Object> list=new ArrayList<>();
        while (true){
            list.add(new HeapSize());
            Thread.sleep(10);
        }
    }
}

CMS

‐Xloggc:d:/gc‐cms‐%t.log ‐Xms50M ‐Xmx50M ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐XX:+PrintGCDetails ‐XX:+P rintGCDateStamps ‐XX:+PrintGCTimeStamps ‐XX:+PrintGCCause ‐XX:+UseGCLogFileRotation ‐XX:NumberOfGCLogFiles=10 ‐XX:GCLogFileSize=100M  ‐XX:+UseParNewGC ‐XX:+UseConcMarkSweepGC

在这里插入图片描述

G1

 ‐Xloggc:d:/gc‐g1‐%t.log ‐Xms50M ‐Xmx50M ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐XX:+PrintGCDetails ‐XX:+Pr intGCDateStamps ‐XX:+PrintGCTimeStamps ‐XX:+PrintGCCause ‐XX:+UseGCLogFileRotation ‐XX:NumberOfGCLogFiles=10 ‐XX:GCLogFileSize=100M ‐XX:+UseG1GC

上面的这些参数,能够帮我们查看分析GC的垃圾收集情况。但是如果GC日志很多很多,成千上万行。就算你一目十行, 看完了,脑子也是一片空白。所以我们可以借助一些功能来帮助我们分析,这里推荐一个gceasy(https://gceasy.io),可以 上传gc文件,然后他会利用可视化的界面来展现GC情况。具体下图所示
在这里插入图片描述
上图我们可以看到年轻代,老年代,以及永久代的内存分配,和最大使用情况。
在这里插入图片描述
上图我们可以看到堆内存在GC之前和之后的变化,以及其他信息。 这个工具还提供基于机器学习的JVM智能优化建议,当然现在这个功能需要付费
在这里插入图片描述

JVM参数汇总查看命令

java -XX:PrintFlagsInitial 打印所有参数选项的默认值
java -XX:PrintFlagsFinal 打印所有参数选项运行时生效的值
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值