JVM调优

作者: 我犟不过你 | 来源:发表于2020-12-21 15:40 被阅读0次

    一、常用参数

    oralce官方参数参考:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

    1.1 HotSpot参数分类

    标准: - 开头,所有的HotSpot都支持
    非标准:-X 开头,特定版本HotSpot支持特定命令
    不稳定:-XX 开头,下个版本可能取消
    

    1.2 调优小程序

    package com.cloud.bssp.jvm;
    
    import java.util.LinkedList;
    import java.util.List;
    
    /**
     * 调优小程序
     *
     * @date: 2020/12/16
     * @author weirx
     * @version 3.0
     */
    public class Tuning {
        public static void main(String[] args) {
            System.out.println("Tuning...!");
            List list = new LinkedList();
            for (; ; ) {
                byte[] bytes = new byte[1024 * 1024];
                list.add(bytes);
            }
        }
    }
    

    本文以idea作为工具,可以在启动main方法时指定参数:

    idea配置

    1.3 常用简单参数

    -XX:+PrintFlagsWithComments:显示所有-XX参数,只有debug版本能用,这里不做演示了。
    -XX:+PrintCommandLineFlags:查看当前jvm使用的优化参数。

    -XX:InitialHeapSize=258062528 -XX:MaxHeapSize=4129000448 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC 
    Connected to the target VM, address: '127.0.0.1:49379', transport: 'socket'
    Tuning...!
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at com.cloud.bssp.jvm.Tuning.main(Tuning.java:18)
    Disconnected from the target VM, address: '127.0.0.1:49379', transport: 'socket'
    

    -Xms:堆最小内存。
    -Xmx:堆最大内存。
    -Xmn:年轻代内存。
    -Xss:线程内存大小,即栈的大小。
    -XX:+PrintGC:打印程序GC过程的日志。

    Tuning...!
    [GC (Allocation Failure)  63340K->56175K(243712K), 0.0132497 secs]
    [GC (Allocation Failure)  119881K->119182K(307712K), 0.0152269 secs]
    [Full GC (Ergonomics)  119182K->118980K(396800K), 0.0249995 secs]
    [GC (Allocation Failure)  246922K->244134K(396800K), 0.0244529 secs]
    [Full GC (Ergonomics)  244134K->243911K(599552K), 0.0210220 secs]
    [GC (Allocation Failure)  371326K->371145K(690688K), 0.0208859 secs]
    [Full GC (Ergonomics)  371145K->370892K(857600K), 0.0073060 secs]
    [GC (Allocation Failure)  590215K->590287K(878080K), 0.0354514 secs]
    [Full GC (Ergonomics)  590287K->590036K(1188352K), 0.0103098 secs]
    [GC (Allocation Failure)  829215K->828888K(1322496K), 0.0332829 secs]
    [Full GC (Ergonomics)  828888K->828637K(1623552K), 0.0094309 secs]
    [GC (Allocation Failure)  1201520K->1201635K(1623552K), 0.0551381 secs]
    [Full GC (Ergonomics)  1201635K->1201387K(2108416K), 0.0126250 secs]
    [GC (Allocation Failure)  1574277K->1574385K(2386944K), 0.0584038 secs]
    [Full GC (Ergonomics)  1574385K->1574138K(2832896K), 0.0163265 secs]
    [GC (Allocation Failure)  2226011K->2206475K(2860544K), 0.0954041 secs]
    [Full GC (Ergonomics)  2206475K->2206302K(3351040K), 0.2683199 secs]
    [Full GC (Ergonomics)  2857931K->2857590K(3351040K), 0.0929544 secs]
    [Full GC (Ergonomics)  3340309K->3339912K(3351040K), 0.0795484 secs]
    [Full GC (Allocation Failure)  3339912K->3339860K(3351040K), 0.3918795 secs]
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at com.cloud.bssp.jvm.Tuning.main(Tuning.java:18)
    
    Process finished with exit code 1
    
    

    -XX:+PrintGCDetails:打印程序GC过程的详细日志,同时打印Heap(堆)的内存信息。

    Tuning...!
    [GC (Allocation Failure) [PSYoungGen: 63340K->9973K(74240K)] 63340K->56062K(243712K), 0.0098700 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
    [GC (Allocation Failure) [PSYoungGen: 73679K->9596K(138240K)] 119768K->119182K(307712K), 0.0140132 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
    [Full GC (Ergonomics) [PSYoungGen: 9596K->0K(138240K)] [ParOldGen: 109585K->118980K(260096K)] 119182K->118980K(398336K), [Metaspace: 3553K->3553K(1056768K)], 0.0289546 secs] [Times: user=0.08 sys=0.00, real=0.03 secs] 
    [GC (Allocation Failure) [PSYoungGen: 127941K->9408K(138240K)] 246922K->244102K(398336K), 0.0278171 secs] [Times: user=0.05 sys=0.09, real=0.03 secs] 
    [Full GC (Ergonomics) [PSYoungGen: 9408K->0K(138240K)] [ParOldGen: 234694K->243911K(464896K)] 244102K->243911K(603136K), [Metaspace: 3553K->3553K(1056768K)], 0.0249985 secs] [Times: user=0.08 sys=0.00, real=0.03 secs] 
    [GC (Allocation Failure) [PSYoungGen: 127415K->9472K(227328K)] 371326K->371145K(692224K), 0.0261426 secs] [Times: user=0.03 sys=0.06, real=0.03 secs] 
    [Full GC (Ergonomics) [PSYoungGen: 9472K->0K(227328K)] [ParOldGen: 361673K->370892K(632320K)] 371145K->370892K(859648K), [Metaspace: 3553K->3553K(1056768K)], 0.0071956 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
    [GC (Allocation Failure) [PSYoungGen: 217235K->9472K(246272K)] 588127K->588239K(878592K), 0.0319854 secs] [Times: user=0.13 sys=0.11, real=0.03 secs] 
    [Full GC (Ergonomics) [PSYoungGen: 9472K->0K(246272K)] [ParOldGen: 578767K->587988K(940032K)] 588239K->587988K(1186304K), [Metaspace: 3553K->3553K(1056768K)], 0.0093061 secs] [Times: user=0.00 sys=0.02, real=0.01 secs] 
    [GC (Allocation Failure) [PSYoungGen: 235012K->9472K(379904K)] 823001K->822744K(1319936K), 0.0339853 secs] [Times: user=0.09 sys=0.14, real=0.03 secs] 
    [Full GC (Ergonomics) [PSYoungGen: 9472K->0K(379904K)] [ParOldGen: 813272K->822493K(1235968K)] 822744K->822493K(1615872K), [Metaspace: 3553K->3553K(1056768K)], 0.0088443 secs] [Times: user=0.09 sys=0.03, real=0.01 secs] 
    [GC (Allocation Failure) [PSYoungGen: 369664K->9472K(379904K)] 1192157K->1189347K(1615872K), 0.0535293 secs] [Times: user=0.09 sys=0.24, real=0.05 secs] 
    [Full GC (Ergonomics) [PSYoungGen: 9472K->0K(379904K)] [ParOldGen: 1179874K->1189099K(1712128K)] 1189347K->1189099K(2092032K), [Metaspace: 3553K->3553K(1056768K)], 0.0125591 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
    [GC (Allocation Failure) [PSYoungGen: 369664K->9472K(656896K)] 1558763K->1555953K(2369024K), 0.0568648 secs] [Times: user=0.14 sys=0.28, real=0.06 secs] 
    [Full GC (Ergonomics) [PSYoungGen: 9472K->0K(656896K)] [ParOldGen: 1546480K->1555705K(2150912K)] 1555953K->1555705K(2807808K), [Metaspace: 3553K->3553K(1056768K)], 0.0134233 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
    [GC (Allocation Failure) [PSYoungGen: 646434K->9760K(656896K)] 2202140K->2182955K(2830848K), 0.0870960 secs] [Times: user=0.19 sys=0.42, real=0.09 secs] 
    [Full GC (Ergonomics) [PSYoungGen: 9760K->9563K(656896K)] [ParOldGen: 2173194K->2173185K(2688512K)] 2182955K->2182749K(3345408K), [Metaspace: 4049K->4049K(1056768K)], 0.2665942 secs] [Times: user=1.53 sys=0.03, real=0.27 secs] 
    [Full GC (Ergonomics) [PSYoungGen: 656159K->140636K(656896K)] [ParOldGen: 2173185K->2688280K(2688512K)] 2829345K->2828917K(3345408K), [Metaspace: 4049K->4049K(1056768K)], 0.1014966 secs] [Times: user=0.30 sys=0.33, real=0.10 secs] 
    [Full GC (Ergonomics) [PSYoungGen: 645749K->645488K(656896K)] [ParOldGen: 2688280K->2688280K(2688512K)] 3334030K->3333768K(3345408K), [Metaspace: 4049K->4049K(1056768K)], 0.0848774 secs] [Times: user=0.42 sys=0.02, real=0.09 secs] 
    [Full GC (Ergonomics) [PSYoungGen: 646656K->646512K(656896K)] [ParOldGen: 2688280K->2688280K(2688512K)] 3334936K->3334792K(3345408K), [Metaspace: 4049K->4049K(1056768K)], 0.0113479 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
    [Full GC (Allocation Failure) [PSYoungGen: 646512K->646477K(656896K)] [ParOldGen: 2688280K->2688262K(2688512K)] 3334792K->3334740K(3345408K), [Metaspace: 4049K->4049K(1056768K)], 0.4267966 secs] [Times: user=2.25 sys=0.06, real=0.43 secs] 
    Heap
     PSYoungGen      total 656896K, used 646656K [0x000000076df80000, 0x00000007a9300000, 0x00000007c0000000)
      eden space 646656K, 100% used [0x000000076df80000,0x0000000795700000,0x0000000795700000)
      from space 10240K, 0% used [0x0000000795700000,0x0000000795700000,0x0000000796100000)
      to   space 10240K, 0% used [0x00000007a8900000,0x00000007a8900000,0x00000007a9300000)
     ParOldGen       total 2688512K, used 2688266K [0x00000006c9e00000, 0x000000076df80000, 0x000000076df80000)
      object space 2688512K, 99% used [0x00000006c9e00000,0x000000076df42b68,0x000000076df80000)
     Metaspace       used 4079K, capacity 4568K, committed 4864K, reserved 1056768K
      class space    used 445K, capacity 460K, committed 512K, reserved 1048576K
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at com.cloud.bssp.jvm.Tuning.main(Tuning.java:18)
    

    -XX:+UseConcMarkSweepGC:使用CMS垃圾回收器,当设置该参数时会默认使用ParNew年轻代回收器。

    -XX:InitialHeapSize=258062528 -XX:MaxHeapSize=4129000448 -XX:MaxNewSize=697933824 -XX:MaxTenuringThreshold=6 -XX:OldPLABSize=16 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:-UseLargePagesIndividualAllocation -XX:+UseParNewGC 
    Tuning...!
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at com.cloud.bssp.jvm.Tuning.main(Tuning.java:18)
    

    -XX:+PrintFlagsInitial:默认参数值。
    -XX:+PrintFlagsFinal:最终参数值。
    -XX:+PrintFlagsFinal | grep xxx:找到对应的参数
    -XX:+PrintFlagsFinal -version |grep GC

    二、调优

    2.1 基本概念

    1、区分概念:内存泄漏memory leak内存溢出out of memory
    2、吞吐量:用户代码时间 /(用户代码执行时间 + 垃圾回收时间)。
    3、 响应时间:STW越短,响应时间越好。

    目前两种常用方案:
    吞吐量:PS + PO
    响应时间:G1

    2.2 如何调优?

    调优,到底应该吞吐量优先?还是响应时间优先?还是在满足一定响应时间的情况下,能达到多大的吞吐量?

    到底什么是调优?可以从下面三个层面进行分析:
    1、根据需求进行JVM规划和预调优
    2、优化JVM运行环境(慢,卡顿)
    3、解决JVM运行过程中出现的各种问题(OOM)

    2.2.1 根据需求进行JVM规划和预调优

    重点:调优应该从结合业务场景开始,确定不同业务场景是看中响应时间还是吞吐量。
    监控方式:压测。

    调优的步骤:
    1)熟悉业务场景,选择合适的垃圾回收器

    响应时间,需要给用户做出响应:CMS G1 ZGC
    吞吐量 = 用户时间 /( 用户时间 + GC时间:PS + PO
    

    2)计算内存需求
    3)选定cpu(越多越好)
    4)设定年代大小
    5)设定日志参数

    -Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause
    

    6)观察日志

    2.2.2 优化JVM运行环境与解决JVM线上问题

    将优化与线上问题的解决放在同一章节去讲解,主要介绍一些常用命令和工具:
    从以下四个问题去优化:
    1)系统卡顿
    原因:内存小,导致频繁的发生Full GC,造成系统卡顿。
    解决方案:增加系统内存,但是发现仍然卡顿,频率降低,且卡顿时间更长了。
    更换后仍然卡顿的原因:内存增加,导致full gc的时间更长。
    解决方案:将PS + PO 更换成 G1或PN + CMS。
    2)CPU100%

    1、top命令,找到占用CPU高的进程(举例一个进程:PID-1)。
    2、top -Hp PID-1 查看进程下的线程占用cpu情况(举例该命令查到的线程PID-2)。
    3、将线程PID转换为16进制:printf "%x\n" PID-2(堆栈中,线程id是以16进制存储的)
    3、jstack打印线程的堆栈:jstack PID-1 | grep PID-2
    

    3)内存飙高
    4)JVM监控

    上述3、4两个问题我们通过以下java自带的命令来分析:
    jmap、jstack

    2.2.3 通过arthas工具排查

    详细内容见:http://arthas.gitee.io/

    2.3 各收集器日志分析

    jdk1.8,jvm究竟使用什么垃圾收集器还取决于当前服务器的cpu核心数:
    在多核情况下,使用的是PS + PO
    在单核情况下,使用Serial + Serial Old

    CMS日志分析

    [GC (CMS Initial Mark) [1 CMS-initial-mark: 8511K(13696K)] 9866K(19840K), 0.0040321 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
        //8511 (13696) : 老年代使用(最大)
        //9866 (19840) : 整个堆使用(最大)
    [CMS-concurrent-mark-start]
    [CMS-concurrent-mark: 0.018/0.018 secs] [Times: user=0.01 sys=0.00, real=0.02 secs] 
        //这里的时间意义不大,因为是并发执行
    [CMS-concurrent-preclean-start]
    [CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
        //标记Card为Dirty,也称为Card Marking
    [GC (CMS Final Remark) [YG occupancy: 1597 K (6144 K)][Rescan (parallel) , 0.0008396 secs][weak refs processing, 0.0000138 secs][class unloading, 0.0005404 secs][scrub symbol table, 0.0006169 secs][scrub string table, 0.0004903 secs][1 CMS-remark: 8511K(13696K)] 10108K(19840K), 0.0039567 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
        //STW阶段,YG occupancy:年轻代占用及容量
        //[Rescan (parallel):STW下的存活对象标记
        //weak refs processing: 弱引用处理
        //class unloading: 卸载用不到的class
        //scrub symbol(string) table: 
            //cleaning up symbol and string tables which hold class-level metadata and 
            //internalized string respectively
        //CMS-remark: 8511K(13696K): 阶段过后的老年代占用及容量
        //10108K(19840K): 阶段过后的堆占用及容量
    
    [CMS-concurrent-sweep-start]
    [CMS-concurrent-sweep: 0.005/0.005 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
        //标记已经完成,进行并发清理
    [CMS-concurrent-reset-start]
    [CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
        //重置内部结构,为下次GC做准备
    

    G1日志分析

    [GC pause (G1 Evacuation Pause) (young) (initial-mark), 0.0015790 secs]
    //young -> 年轻代 Evacuation-> 复制存活对象 
    //initial-mark 混合回收的阶段,这里是YGC混合老年代回收
       [Parallel Time: 1.5 ms, GC Workers: 1] //一个GC线程
          [GC Worker Start (ms):  92635.7]
          [Ext Root Scanning (ms):  1.1]
          [Update RS (ms):  0.0]
             [Processed Buffers:  1]
          [Scan RS (ms):  0.0]
          [Code Root Scanning (ms):  0.0]
          [Object Copy (ms):  0.1]
          [Termination (ms):  0.0]
             [Termination Attempts:  1]
          [GC Worker Other (ms):  0.0]
          [GC Worker Total (ms):  1.2]
          [GC Worker End (ms):  92636.9]
       [Code Root Fixup: 0.0 ms]
       [Code Root Purge: 0.0 ms]
       [Clear CT: 0.0 ms]
       [Other: 0.1 ms]
          [Choose CSet: 0.0 ms]
          [Ref Proc: 0.0 ms]
          [Ref Enq: 0.0 ms]
          [Redirty Cards: 0.0 ms]
          [Humongous Register: 0.0 ms]
          [Humongous Reclaim: 0.0 ms]
          [Free CSet: 0.0 ms]
       [Eden: 0.0B(1024.0K)->0.0B(1024.0K) Survivors: 0.0B->0.0B Heap: 18.8M(20.0M)->18.8M(20.0M)]
     [Times: user=0.00 sys=0.00, real=0.00 secs] 
    //以下是混合回收其他阶段
    [GC concurrent-root-region-scan-start]
    [GC concurrent-root-region-scan-end, 0.0000078 secs]
    [GC concurrent-mark-start]
    //无法evacuation,进行FGC
    [Full GC (Allocation Failure)  18M->18M(20M), 0.0719656 secs]
       [Eden: 0.0B(1024.0K)->0.0B(1024.0K) Survivors: 0.0B->0.0B Heap: 18.8M(20.0M)->18.8M(20.0M)], [Metaspace: 38
    76K->3876K(1056768K)] [Times: user=0.07 sys=0.00, real=0.07 secs]
    

    三、常见问题分析

    1. -XX:MaxTenuringThreshold控制的是什么?

    该参数主要是控制新生代需要经历多少次GC晋升到老年代中的最大阈值。

    2. 生产环境中,倾向于将最大堆内存和最小堆内存设置为?

    相同,避免在每次GC之后去动态调整堆的大小。

    3. JDK1.8默认的垃圾回收器是:

    PS+PO

    4. 什么是响应时间优先?

    快速给用户响应,本质是降低STW。
    推荐垃圾回收器:CMS + ParNew,G1,ZGC

    5. 什么是吞吐量优先?

    不要求快速给用户响应,能处理更多的任务,但是STW时间增长。
    推荐垃圾回收器:PS + PO。

    6. ParNew和PS的区别是什么?

    ParNew主要为了配合CMS所使用的多线程年轻代垃圾回收器。
    PS关注点为吞吐量,而CMS关注点在于更快的响应时间。

    7. ParNew和ParallelOld的区别是什么?

    ParNew主要为了配合CMS所使用的多线程年轻代垃圾回收器。
    ParallelOld是多线程的老年代回收器。
    其算法也不相同。

    8. 长时间计算的场景应该选择:A:停顿时间 B: 吞吐量

    B

    9. 大规模电商网站应该选择:A:停顿时间 B: 吞吐量

    A

    10. HotSpot的垃圾收集器最常用有哪些?

    Serial + serial Old
    PS + PO
    ParNew + CMS
    G1
    ZGC

    11. 常见的HotSpot垃圾收集器组合有哪些?

    Serial + serial Old
    PS + PO
    ParNew + CMS
    G1
    ZGC

    12. JDK1.7 1.8 1.9的默认垃圾回收器是什么?如何查看?

    jdk1.7 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
    jdk1.8 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
    jdk1.9 默认垃圾收集器G1

    -XX:+PrintCommandLineFlagsjvm参数可查看默认设置收集器类型
    -XX:+PrintGCDetails亦可通过打印的GC日志的新生代、老年代名称判断

    13. 所谓调优,到底是在调什么?

    吞吐量和响应时间
    结合业务,环境优化,线上问题的解决

    14. 如果采用PS + ParrallelOld组合,怎么做才能让系统基本不产生FGC

    增加内存,但是PS + PO的组合并不是内存越大越好,有其限度,按经验来讲最大到几个G。

    增加年轻代的大小,
    增加年轻代的比例,
    增加gc年龄
    这三个增加可以使垃圾尽量在年轻代被回收。

    代码层面减少内存泄漏、死锁。

    15. 如果采用ParNew + CMS组合,怎样做才能够让系统基本不产生FGC

    增加内存,要比PS + PO大的多,按经验来讲最大到几十个G。

    增加年轻代的大小,
    增加年轻代的比例,
    增加gc年龄
    这三个增加可以使垃圾尽量在年轻代被回收。

    代码层面减少内存泄漏、死锁。

    16. G1是否分代?G1垃圾回收器会产生FGC吗?

    G1是逻辑分代,物理不分代,混合回收,也会产生FullGC。

    17. 如果G1产生FGC,你应该做什么?

    减少代码中的大对象,增加region区域

    扩内存

    提高CPU性能(回收的快,业务逻辑产生对象的速度固定,垃圾回收越快,内存空间越大)

    降低MixedGC触发的阈值,让MixedGC提早发生(默认是45%)

    18. 问:生产环境中能够随随便便的dump吗?

    不能,会导致卡顿

    19. 问:常见的OOM问题有哪些?

    堆,栈,元空间

    相关文章

      网友评论

        本文标题:JVM调优

        本文链接:https://www.haomeiwen.com/subject/zkingktx.html