JVM 组成及常见调优工具入门

1.JVM 组成

1.参考 腾讯课堂 jvm 教程,该课程详解了 jvm 组成和垃圾收集机制,调优工具 jvisualvm 和 arthas 基本使用,以及 jvm 调优的相关场景(最后一节可以不看,大部分时长都是在推销课程)
2. JVM 内部组成关系图在这里插入图片描述
3. JVM 常用参数

1.堆栈相关配置
-Xmx512m   整堆最大为512MB,超出报OOM
-Xmn256m   新生代大小,新生代太小会频繁full GC
-Xms256m   初始堆大小
-Xss256k   线程栈最大值,栈太小容易发生栈溢出
-XX:NewRatio = 2   默认新生代占整堆1/3,老年代占2/3,老年代:新生代 = 2:1
-XX:SurvivorRatio = 8   默认Eden区占整个新生代4/5Eden:s0:s1 = 8:1:1

2.配置垃圾收集器
-XX:UseSerialGC 新生代使用serial,老年代使用serial old
-XX:UseParallelGC 新生代使用Parallel Scanvenge,老年代使用Parallel Old
-XX:UseParNewGC:新生代使用 ParNew,老年代使用CMS
-XX:UseConcMarkSweepGC:老年代使用CMS
-XX:UseG1GC:使用 G1 收集器

3.条件触发配置
-XX:+HeapDumpOnOutOfMemoryError  当发生内存溢出时导出堆信息到指定文件
-XX:-HeapDumpOnOutOfMemoryError  取消上面的配置
-XX:+HeapDumpBeforeFullGC        Full GC 前导出堆信息到指定文件
-XX:+HeapDumpAfterFullGC         FUll GC 后...
-XX: HeapDumpPath                堆信息导出路径,与上面两个命令联合使用
  1. 设置JVM参数的方式
  • IDEA 里面设置
    在这里插入图片描述
    在这里插入图片描述

  • java -jar …jar 命令启动时设置
    java -jar -Xmx512m -XX:NewRatio=1 app.jar

2.准备工作

1.编写一个会产生死锁的类 LockTest.java 和 一个会报内存溢出的类 GCTest.java,运行

  • LockTest
import java.util.Date;

public class LockTest {
    public static String obj1 = "obj1";
    public static String obj2 = "obj2";
    public static void main(String[] args) {
        LockA la = new LockA();
        new Thread(la).start();
        LockB lb = new LockB();
        new Thread(lb).start();
    }
}
class LockA implements Runnable{
    public void run() {
        try {
            System.out.println(new Date().toString() + " LockA 开始执行");
            while(true){
                synchronized (LockTest.obj1) {
                    System.out.println(new Date().toString() + " LockA 锁住 obj1");
                    Thread.sleep(3000); // 此处等待是给B能锁住机会
                    synchronized (LockTest.obj2) {
                        System.out.println(new Date().toString() + " LockA 锁住 obj2");
                        Thread.sleep(60 * 1000); // 为测试,占用了就不放
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
class LockB implements Runnable{
    public void run() {
        try {
            System.out.println(new Date().toString() + " LockB 开始执行");
            while(true){
                synchronized (LockTest.obj2) {
                    System.out.println(new Date().toString() + " LockB 锁住 obj2");
                    Thread.sleep(3000); // 此处等待是给A能锁住机会
                    synchronized (LockTest.obj1) {
                        System.out.println(new Date().toString() + " LockB 锁住 obj1");
                        Thread.sleep(60 * 1000); // 为测试,占用了就不放
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • GCTest
import java.util.ArrayList;

public class GCtest {
    byte[] arr = new byte[1024*100];
    public static void main(String[] args) throws InterruptedException {
        ArrayList<GCtest> gctests = new ArrayList<>();
        while(true){
            gctests.add(new GCtest());
            Thread.sleep(10);
        }
    }
}

3.jdk 内置工具 jps、jmap、jstat、jstack

这些命令可以在 cmd 命令行直接使用,如果报jxx 不是内部命令或外部命令...错误,可参考这篇文章解决

  1. jps(JVM Process Status Tool):用于输出当前正在运行的 JVM 进程信息
  • jps -l 输出主类的全名,如果进程执行的是Jar包,输出Jar路径
    在这里插入图片描述
  1. jmap(Memory Map for Java):用于生成堆转储快照(一般称为heapdump或dump文件)
  • 查看运行的JAVA进程堆内存使用情况: jmap -heap 102144
    在这里插入图片描述
  • 手动导出dump:jmap -dump:format=b,file=heap.hprof 102144
    在这里插入图片描述
  1. jstat:用来监视VM内存内的各种堆和非堆的大小及其内存使用量,以及加载类的数量
    jstat -class 102144 1000 10(每隔1秒监控一次,一共做10次):统计class loader行为信息
    jstat -gc 102144 2000 20 (每隔2秒监控一次,共20次):统计jdk gc时heap信息
    在这里插入图片描述
  2. jstack:可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码
    jstack pid

4.jvisualvm

上面的命令比较繁琐,且命令行界面不够简洁明了,JVisualVM是JDK自带的性能检测工具,路径在%JAVA_HOME%/bin下面。双击打开,可以看到当前在本地正在运行的jvm进程,点击上面写的那个死锁类,可以看到该进程的cpu、内存、类加载、线程信息
在这里插入图片描述线程监视:点击线程即可当前进程所有的线程,右下角根据不同的颜色可以区分线程的不同状态,可以看到jvisualvm监测到死锁,点击右边的 线程Dump,可以定位到死锁代码
在这里插入图片描述jvisualvm 还可以解析jmap命令产生的dump文件,找到dump文件,改为*.hprof 后缀,点击左上角的 文件–>装入 ,在这里插入图片描述
文件类型改为Dump 堆,找到生成的dump文件,确定,即可解析dump文件

5.arthas

上面的工具都是jdk自带的,在没有其他工具可用的情况下使用,一般情况下,在现在排查线上问题用arthas 比较多
在这里插入图片描述

arthas 安装,下载 arthas的 jar 包后,java -jar arthas-boot.jar 命令运行即可运行arthas,选择要监测的进程,出现如下页面表示启动成功
在这里插入图片描述
arthas 常用命令

  • dashboard展示当前进程的信息
    在这里插入图片描述

  • thread 1会打印线程ID 1的栈,通常是main函数的线程
    在这里插入图片描述

  • jad 反编译:jad jvm.GCTest,可用来检验自己写的代码是否被运维正确发布
    在这里插入图片描述
    其他arthas进阶使用,可参考 arthas 文档

6.常见线上调优场景

  1. 线上几分钟就进行一次 Full GC,由于 Stop The World 造成系统频繁卡顿
    可能的原因:新生代大小不够,导致大对象直接进入进入老年代,很快占满老年代导致 Full GC
    解决办法:调大新生代大小

  2. 发生 OutOfMemory Error
    可能的原因:有部分对象过大,比如从数据库查出几十万条数据,将结果放在 ArrayList 里面,导致list过大
    解决办法:使用 jmap 手动输出 dump 文件,使用 mat 或者 jvisualvm 解析dump 文件,查看堆内存使用情况,定位大对象

  3. 监测到进程内有大量线程处于阻塞状态
    可能的原因:多线程环境下,锁的粒度太大,锁住了不该锁住的资源,导致大量线程阻塞
    解决办法:定位到问题代码所在位置,只锁该锁的资源,减小锁粒度

  4. 线程死锁
    jvisualvm 可以发现死锁并定位到死锁位置

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值