• jvm调优思路


    文章目录


    JVM 常用命令

    JDK监控和故障处理命令有 jpsjstatjmapjhatjstackjinfo

    jps:显示指定系统内所有的 HotSpot 虚拟机进程。

    jstat(JVM statistics Monitoring)是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT 编译等运行数据。

    jstat -options

    • -class 用于查看类加载情况的统计
    • -compiler 用于查看HotSpot中即时编译器编译情况的统计
    • -gc 用于查看JVM中堆的垃圾收集情况的统计
    • -gccapacity 用于查看新生代、老生代及持久代的存储容量情况
    • -gcmetacapacity 显示metaspace的大小
    • -gcnew 用于查看新生代垃圾收集的情况
    • -gcnewcapacity 用于查看新生代存储容量的情况
    • -gcold 用于查看老生代及持久代垃圾收集的情况
    • -gcoldcapacity 用于查看老生代的容量
    • -gcutil 显示垃圾收集信息
    • -gccause 显示垃圾回收的相关信息(通-gcutil),同时显示最后一次仅当前正在发生的垃圾收集的原因
    • -printcompilation 输出JIT编译的方法信息

    例:

    [root@host /]# jstat -gc 500991
     S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CSU   YGC     YGCT    FGC    FGCT     GCT
    512.0  1024.0  0.0   600.1  90112.0  72763.9   729088.0   31753.9   69720.0 66252.1 8320.0 7738.2    367    4.329   3      0.739    5.067
    
    • 1
    • 2
    • 3

    jmap:可dump堆内容进行分析

    常用命令:

    jmap [pid] # 查看具体情况
    
    jmap -dump:live,format=b,file=xxx.xxx [pid] #将当前Java进程的内存占用情况导出来
     
    jmap -histo:live [pid] >a.log  # 显示 存活 得对象信息
    
    jmap -finalizerinfo [pid] # 查看 等待执行finalize 方法的数量
    
    jmap -heap [pid] # 堆摘要信息
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    [root@host xxx]# jmap -heap 500991
    Attaching to process ID 500991, please wait...
    Debugger attached successfully.
    Server compiler detected.
    JVM version is 25.131-b11
    
    using thread-local object allocation.
    Parallel GC with 10 thread(s)
    
    Heap Configuration:
       MinHeapFreeRatio         = 0
       MaxHeapFreeRatio         = 100
       MaxHeapSize              = 16819159040 (16040.0MB)
       NewSize                  = 350748672 (334.5MB)
       MaxNewSize               = 5606211584 (5346.5MB)
       OldSize                  = 702021632 (669.5MB)
       NewRatio                 = 2
       SurvivorRatio            = 8
       MetaspaceSize            = 21807104 (20.796875MB)
       CompressedClassSpaceSize = 1073741824 (1024.0MB)
       MaxMetaspaceSize         = 17592186044415 MB
       G1HeapRegionSize         = 0 (0.0MB)
    
    Heap Usage:
    PS Young Generation
    Eden Space:
       capacity = 92274688 (88.0MB)
       used     = 32007552 (30.5247802734375MB)
       free     = 60267136 (57.4752197265625MB)
       34.68725031072443% used
    From Space:
       capacity = 524288 (0.5MB)
       used     = 482840 (0.46047210693359375MB)
       free     = 41448 (0.03952789306640625MB)
       92.09442138671875% used
    To Space:
       capacity = 1048576 (1.0MB)
       used     = 0 (0.0MB)
       free     = 1048576 (1.0MB)
       0.0% used
    PS Old Generation
       capacity = 746586112 (712.0MB)
       used     = 32515968 (31.0096435546875MB)
       free     = 714070144 (680.9903564453125MB)
       4.355287016107795% used
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    在这里插入图片描述

    jhat(JVM Heap Analysis Tool)命令是与 jmap 搭配使用,用来分析 jmap 生成的 dump,jhat 内置了一个微型的 HTTP/HTML 服务器,生成 dump 的分析结果后,可以在浏览器中查看。

    在此要注意,一般不会直接在服务器上进行分析,因为 jhat 是一个耗时并且耗费硬件资源的过程,一般把服务器生成的 dump 文件复制到本地或其他机器上进行分析。

    参考:https://blog.csdn.net/weixin_42272869/article/details/124190855

    正常我们是通过jmap dump下堆内存使用文件后使用idea插件jprofiler来进行分析。

    Mac安装JProfiler和IDE集成 记得单独整理下。。。

    通过下面命令dump下来快照文件,通过jprofiler进行分析:

    jmap -dump:live,format=b,file=dump.bin 500991
    
    • 1

    在这里插入图片描述

    jstack 用于生成 java 虚拟机当前时刻的线程快照。

    线程快照是当前 java 虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。

    线程出现停顿的时候通过 jstack 来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。

    调优手段

    • 选择合适的垃圾回收器
      • CPU 单核:那么毫无疑问 Serial 垃圾收集器是你唯一的选择;
      • CPU 多核:关注吞吐量 ,那么选择 PS+PO 组合;
      • CPU 多核:关注用户停顿时间,JDK 版本 1.6 或者 1.7,那么选择 CMS;
      • CPU 多核:关注用户停顿时间,JDK1.8 及以上,JVM 可用内存 6G 以上,那么选择 G1。
        //设置Serial垃圾收集器(新生代)
         开启:-XX:+UseSerialGC
         
         //设置PS+PO,新生代使用功能Parallel Scavenge 老年代将会使用Parallel Old收集器
         开启 -XX:+UseParallelOldGC
         
         //CMS垃圾收集器(老年代)
         开启 -XX:+UseConcMarkSweepGC
         
         //设置G1垃圾收集器
         开启 -XX:+UseG1GC
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
    • 调整内存大小
      • 现象:垃圾收集频率非常频繁。
      • 原因:如果内存太小,就会导致频繁的需要进行垃圾收集才能释放出足够的空间来创建新的对象,所以增加堆内存大小的效果是非常显而易见的。
      • 注意:如果垃圾收集次数非常频繁,但是每次能回收的对象非常少,那么这个时候并非内存太小,而可能是内存泄露导致对象无法回收,从而造成频繁 GC。
        //设置堆初始值
         指令1:-Xms2g
         指令2:-XX:InitialHeapSize=2048m
         
         //设置堆区最大值
         指令1:`-Xmx2g` 
         指令2: -XX:MaxHeapSize=2048m
         
         //新生代内存配置
         指令1:-Xmn512m
         指令2:-XX:MaxNewSize=512m
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
    • 设置符合预期的停顿时间
      • 现象:程序间接性的卡顿
      • 原因:如果没有确切的停顿时间设定,垃圾收集器以吞吐量为主,那么垃圾收集时间就会不稳定。
      • 注意:不要设置不切实际的停顿时间,单次时间越短也意味着需要更多的 GC 次数才能回收完原有数量的垃圾.
        //GC停顿时间,垃圾收集器会尝试用各种手段达到这个时间
        -XX:MaxGCPauseMillis 
        
        • 1
        • 2
    • 调整内存区域大小比率
      • 现象:某一个区域的GC频繁,其他都正常。
      • 原因:如果对应区域空间不足,导致需要频繁GC来释放空间,在JVM堆内存无法增加的情况下,可以调整对应区域的大小比率。
      • 注意:也许并非空间不足,而是因为内存泄造成内存无法回收,从而导致 GC 频繁。
        //survivor区和Eden区大小比率
        指令:-XX:SurvivorRatio=6  //S区和Eden区占新生代比率为1:6,两个S区2:6
        
        //新生代和老年代的占比
        -XX:NewRatio=4  //表示新生代:老年代 = 1:4 即老年代占整个堆的4/5;默认值=2
        
        • 1
        • 2
        • 3
        • 4
        • 5
    • 调整对象升老年代的年龄
      • 现象:老年代频繁 GC,每次回收的对象很多。
      • 原因:如果升代年龄小,新生代的对象很快就进入老年代了,导致老年代对象变多,而这些对象其实在随后的很短时间内就可以回收,这时候可以调整对象的升级代年龄,让对象不那么容易进入老年代解决老年代空间不足频繁 GC 问题。
      • 注意:增加了年龄之后,这些对象在新生代的时间会变长可能导致新生代的 GC 频率增加,并且频繁复制这些对象新生的 GC 时间也可能变长。
        //进入老年代最小的GC年龄,年轻代对象转换为老年代对象最小年龄值,默认值7
        -XX:InitialTenuringThreshol=7 
        
        • 1
        • 2
    • 调整大对象的标准
      • 现象:老年代频繁 GC,每次回收的对象很多,而且单个对象的体积都比较大。
      • 原因:如果大量的大对象直接分配到老年代,导致老年代容易被填满而造成频繁 GC,可设置对象直接进入老年代的标准。
      • 注意:这些大对象进入新生代后可能会使新生代的 GC 频率和时间增加。
        //新生代可容纳的最大对象,大于则直接会分配到老年代,0代表没有限制。
        -XX:PretenureSizeThreshold=1000000 
        
        • 1
        • 2
    • 调整GC的触发时机
      • 现象:CMS,G1 经常 Full GC,程序卡顿严重。
      • 原因:G1 和 CMS 部分 GC 阶段是并发进行的,业务线程和垃圾收集线程一起工作,也就说明垃圾收集的过程中业务线程会生成新的对象,所以在 GC 的时候需要预留一部分内存空间来容纳新产生的对象,如果这个时候内存空间不足以容纳新产生的对象,那么JVM就会停止并发收集暂停所有业务线程(STW)来保证垃圾收集的正常运行。这个时候可以调整GC触发的时机(比如在老年代占用 60% 就触发 GC),这样就可以预留足够的空间来让业务线程创建的对象有足够的空间分配。
      • 注意:提早触发 GC 会增加老年代 GC 的频率。
        //使用多少比例的老年代后开始CMS收集,默认是68%,如果频繁发生SerialOld卡顿,应该调小
        -XX:CMSInitiatingOccupancyFraction
         
        //G1混合垃圾回收周期中要包括的旧区域设置占用率阈值。默认占用率为 65%
        -XX:G1MixedGCLiveThresholdPercent=65 
        
        • 1
        • 2
        • 3
        • 4
        • 5
    • 调整 JVM本地内存大小
      • 现象:GC 的次数、时间和回收的对象都正常,堆内存空间充足,但是报 OOM
      • 原因:JVM 除了堆内存之外还有一块堆外内存,这片内存也叫本地内存,可是这块内存区域不足了并不会主动触发 GC,只有在堆内存区域触发的时候顺带会把本地内存回收了,而一旦本地内存分配不足就会直接报 OOM 异常。
      • 注意:本地内存异常的时候除了上面的现象之外,异常信息可能是 OutOfMemoryError:Direct buffer memory。解决方式除了调整本地内存大小之外,也可以在出现此异常时进行捕获,手动触发 GC(System.gc())。
        XX:MaxDirectMemorySize
        
        • 1
  • 相关阅读:
    自考重庆工商大学难不难?
    2024年腾讯云2核4G5M轻量服务器性能评测,多维度测试
    金仓数据库 KingbaseES异构数据库移植指南 (3. KingbaseES移植能力支撑体系)
    360T7路由器进行WiFi无线中继教程
    Codeforces Round 932 (Div. 2) ---- E. Distance Learning Courses in MAC ---- 题解
    超详细的cookie属性HttpOnly和SameSite引起的漏洞解决方案
    【云原生】简单谈谈海量数据采集组件Flume的理解
    Java设计模式 | 七大原则之迪米特法则
    LeetCode300:最长递增子序列
    刷爆力扣之检查数组对是否可以被 k 整除
  • 原文地址:https://blog.csdn.net/qq_24095055/article/details/126437698