vlambda博客
学习文章列表

死磕Java虚拟机-性能调优实战篇

Java命令分为如下三种


1.  以java - 开头:标准参数


2.  以java -X 开头:非标参数

死磕Java虚拟机-性能调优实战篇


3.  以java -XX 开头:性能调优主要用这个开头的参数,但是无法找到相关参数的帮助文档,下面我教大家几个常用的命令


  • -XX:+UseSerialGC = Serial New (DefNew) + Serial Old


      小型程序。默认情况下不会是这种选项,HotSpot会根据计算及配置和          JDK版本自动选择收集器


  • -XX:+UseParNewGC = ParNew + SerialOld


      这个组合已经很少用(在某些版本中已经废弃)

https://stackoverflow.com/questions/34962257/why-remove-support-for-parnewserialold-anddefnewcms-in-the-future


  • -XX:+UseConc(urrent)MarkSweepGC = ParNew + CMS + Serial Old


  • -XX:+UseParallelGC = Parallel Scavenge + Parallel Old (1.8默认) 【PS + SerialOld】


  • -XX:+UseParallelOldGC = Parallel Scavenge + Parallel Old


  • -XX:+UseG1GC = G1


  • Linux中没找到默认GC的查看方法,而windows中会打印UseParallelGC


       java -XX:+PrintCommandLineFlags -version

       通过GC的日志来分辨


  • Linux下1.8版本默认的垃圾回收器到底是什么?


       1.8.0_181 默认(看不出来)Copy MarkCompact

       1.8.0_222 默认 PS + PO


java -XX:+PrintFlagsFinal   会打印所有的JVM参数 


4.  小案例如下:

package com.fengyaof.jvm.sikejvm;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class FullGC_Problem01 {

    private static class CardInfo {
        BigDecimal price = new BigDecimal(0.0);
        String name = "张三";
        int age = 5;
        Date birthday = new Date();

        public void m() {

        }
    }

    private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50,
            new ThreadPoolExecutor.DiscardPolicy());

    public static void main(String[] args) throws InterruptedException {
        executor.setMaximumPoolSize(50);

        for (; ; ) {
            modelFit();
            Thread.sleep(100);
        }

    }

    private static void modelFit() {
        List<CardInfo> taskList = getAllCardInfo();
        taskList.forEach(info -> {
            executor.scheduleWithFixedDelay(new Runnable() {
                @Override
                public void run() {
                    info.m();
                }
            }, 23, TimeUnit.SECONDS);
        });
    }

    private static List<CardInfo> getAllCardInfo() {
        List<CardInfo> taskList = new ArrayList<>();

        for (int i = 0; i < 100; i++) {
            CardInfo info = new CardInfo();
            taskList.add(info);
        }

        return taskList;
    }

}


我们在Linux上面用这个命令去运行:


java -Xms100M -Xmx100M -XX:+PrintGC com.fengyaof.jvm.sikejvm.FullGC_Problem01


命令运行如下: 我们可以分析出程序运行到一定的时候,Full GC每次回收的内存是2k,非常少。

死磕Java虚拟机-性能调优实战篇


我们看看top运行的内存变化:CPU上升的很高,内存消耗百分比(MEM)没有明显变化说明垃圾基本没有回收。


死磕Java虚拟机-性能调优实战篇


那么我们如何定位问题:

1) 先使用下jps 查看进程号

死磕Java虚拟机-性能调优实战篇


2) 打印进程号的信息:jinfo 1471


3) 使用命令 jstat -gc 1471 1000 (1471代表进程号,1000代表刷新频率)


4) 把进程里面所有的线程列举出来 jstack 1471 

    这个命令可以检查死锁:

死磕Java虚拟机-性能调优实战篇


5)  jmap -histo 1697 | head -20

这个命令可以把类型有多少个对象找出来,这个命令线上不能用,会暂停服务

死磕Java虚拟机-性能调优实战篇


面试经常会问的问题:CPU飙高,内存飙高,内存泄漏,如何排查?其实arthas一个工具就可以搞定


5.  我们用arthas如何进行定位?


arthas启动完成后如下图:

死磕Java虚拟机-性能调优实战篇


arthas常用命令讲解:


1) dashboard  线程飙高怎么排查,可以使用这个命令

死磕Java虚拟机-性能调优实战篇


2) jvm 查看一些基本的信息


3) thread 查看线程的占用情况。

thread中有很好用的命令:找到死锁

thread -b 可以找到死锁


4) 例如微服务里面如何查看哪个服务调用占用的内存多,可是使用下面的命令:

1.  先查询某个类,使用模糊查询:sc *com.fengyaof*

死磕Java虚拟机-性能调优实战篇


2.  查询某个类里面的方法:

sm com.fengyaof.jvm.sikejvm.FullGC_Problem01

死磕Java虚拟机-性能调优实战篇


3.  例如我们对类中某个方法有怀疑,我们可以进行跟踪,使用trace 命令


下面,我教几个arthas重要的命令。


1)  heapdump /root/temp.hprof  把堆导出来做分析

在实际生产过程中,不能使用,服务器会产生暂停。


我们用java自带的工具jvisualvm,把这个堆文件分析一下,如图:


2) jad 反编译

jad com.fengyaof.jvm.sikejvm.FullGC_Problem01

这个命令很好用,在线可以反编译看看代码是不是最新的。


3) 下面有个场景:我发现我们线上环境的某个代码不是最新的,我们该怎么快速替换这个文件呢,不能重启服务。

使用redefine命令,救急使用


我们总结一下:

CPU飙高:jstack,arthas中的thread可以揪出哪个线程飙高,可以GC线程,也可能是业务线程。

内存飙高:jmap,查看类中有多少个对象,或者是dump文件查看。


GC设定日志参数:

-Xloggc:/path/gc.log 

-XX:+UseGCLogFileRotation 

-XX:NumberOfGClogFiles=5 

-XX:GCLogFileSize=20M

-XX:+PrintGCDetails

-XX:+PrintGCDateStamps

-XX:+PrintGCCause


设置OOM的堆存储文件:

-XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath=C:/temp/oom.hprof