JVM

作者: 想成为大师的学徒小纪 | 来源:发表于2022-04-22 17:23 被阅读0次

    一、JVM监控及排查分析命令详解

    1、jps

    JVM Process Status Tool,用于显示指定系统内所有的HotSpot虚拟机进程。

    usage: jps [options] [hostid]     #hostid可以省略
    
    options:
        -l  显示pid和应用程序main class的完整包名或者应用程序的jar路径
        -q  只显示 pid
        -m  显示pid、应用程序main class类名和传递给main方法的参数,在嵌入式jvm上可能是null
        -v  显示pid、应用程序main class类名和传递给jvm的参数
        -V  默认,显示pid和应用程序main class类名
    

    2、jstat

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

    usage: jstat [option] [-t] [-h<lines>] LVMID [interval] [count]
        [interval]: 连续输出的时间间隔
        [count]: 输出的次数
    
    options:
        -class  显示有关类加载器行为的统计信息
        -compiler  显示有关Java HotSpot VM即时编译器行为的统计信息。
        -gc  显示有关垃圾收集堆行为的统计信息。
        -gccapacity  显示各个垃圾回收代容量及其对应空间的统计信息。
        -gccause  显示有关垃圾收集统计信息的摘要(与 -gcutil 相同),以及最后和当前(如果适用)垃圾收集事件的原因。
        -gcnew  显示新生代行为的统计信息。
        -gcnewcapacity  显示有关新生代及其对应空间大小的统计信息。
        -gcold  显示有关老年代行为的统计信息和元空间统计信息。
        -gcoldcapacity  显示有关老年代大小的统计信息。
        -gcmetacapacity  显示有关元空间大小的统计信息。
        -gcutil  显示有关垃圾收集统计信息的摘要。
        -printcompilation  显示Java HotSpot VM编译方法统计信息。
    
    
    -t:将时间戳列显示为输出的第一列。时间戳是自目标JVM启动时间以来的时间。
    -h n:每n个样本(输出行)显示一个列标题,其中n是一个正整数。默认值为0,即显示列标题的第一行数据。
    
    • -class标题字段含义

      Loaded:加载class的数量

      Bytes:加载class占用大小(KB)

      Unloaded:未加载class的数量

      Bytes:未加载class占用大小(KB)

      Time:执行加载class和卸载class操作所花费的时间

    • -compiler标题字段含义

      Compiled:执行的编译任务数

      Failed:执行失败的编译任务数

      Invalid:无效的编译任务数

      Time:执行编译任务所花费的时间

      FailedType:上次编译失败的编译类型

      FailedMethod:上次失败编译的类名和方法

    • -gc标题字段含义

      S0C:survivor0空间当前容量(KB)

      S1C:survivor1空间当前容量(KB)

      S0U:survivor0空间利用容量(KB)

      S1U:survivor1空间利用容量(KB)

      EC:Eden空间当前容量(KB)

      EU:Eden空间利用容量(KB)

      OC:Old空间当前容量(KB)

      OU:Old空间利用容量(KB)

      MC:元空间容量(KB)

      MU:元空间利用容量(KB)

      CCSC:压缩类空间容量(KB)

      CCSU:压缩类空间已使用容量(KB)

      YGC:年轻代垃圾回收次数

      YGCT:年轻代垃圾回收时间

      FGC:full gc次数

      FGCT:full gc耗时

      GCT:总垃圾回收时间

    • -gccapacity标题字段含义

      NGCMN:最小new generation容量(KB),近似年轻代

      NGCMX:最大new generation容量(KB),近似年轻代

      NGC:new generation容量(KB),近似年轻代

      OGCMN:最小老年代容量(KB)

      OGCMX:最大老年代容量(KB)

      OGC:老年代容量(KB)

      MCMN:最小元空间容量(KB)

      MCMX:最大元空间容量(KB)

      CCSMN:压缩类空间最小容量(KB)

      CCSMX:压缩类空间最大容量(KB)

    • -gccause标题字段含义

      S0:survivor0空间利用容量占当前容量的百分比

      S1:survivor1空间利用容量占当前容量的百分比

      E:Eden空间利用容量占当前容量的百分比

      O:Old空间利用容量占当前容量的百分比

      M:元空间利用容量占当前容量的百分比

      CCS:压缩类空间利用率百分比

      YGC:年轻代垃圾回收次数

      YGCT:年轻代垃圾回收时间

      FGC:full gc次数

      FGCT:full gc耗时

      GCT:总垃圾回收时间

      LGCC:上次垃圾回收的原因

      GCC:当前垃圾回收的原因

    • -gcutil标题字段含义

      -gccause标题字段含义一致

    • -gcnew标题字段含义

      TT:晋升阈值

      MTT:最大晋升阈值

      DSS:所需survivor空间大小(KB)

    • -gcnewcapacity标题字段含义

      S0CMX:最大survivor0空间容量(KB)

      S1CMX:最大survivor1空间容量(KB)

      ECMX:最大Eden空间容量(KB)

    • -gcold标题字段含义

      该字段含义在上文中都有

    • -gcoldcapacity标题字段含义

      该字段含义在上文中都有

    • -gcmetacapacity标题字段含义

      该字段含义在上文中都有

    • -printcompilation标题字段含义

      Compiled:最近执行的编译方法任务数

      Size:最近编译方法的字节码的数量

      Type:最近编译的方法的编译类型

      Method:标识最近编译的方法的类名和方法名。方法名是指定类中的方法。

    3、jmap

    打印进程、核心文件或远程调试服务器的共享对象内存映射或堆内存详细信息。

    除此命令外,通过指定-XX:+HeapDumpOnOutOfMemoryError参数,在发生OutOfMemoryError时生成堆dump文件。或者使用hprof命令也可以生成。

    usage: jmap [ options ] pid
           jmap [ options ] executable core
           jmap [ options ] [ pid ] server-id@ ] remote-hostname-or-IP
        executable:生成可执行的核心转储文件
        core:打印内存映射的核心文件
        remote-hostname-or-IP:远程调试服务器主机名或IP地址
        server-id:当多个调试服务器在同一远程主机上运行时使用的可选唯一ID
    
    options:
        <none>  如果不使用任何选项,jmap命令会打印共享对象映射。对于目标JVM中加载的每个共享对象,都会打印共享对象文件的起始地址、映射大小和完整路径
        -dump:[live,] format=b, file=filename
            以hprof二进制格式生成堆转储文件。live子选项是可选的,当指定时,仅转储堆中的活动对象。要浏览堆转储文件,可以使用jhat命令读取。
        -finalizerinfo  打印有关等待回收的对象的信息
        -heap  打印堆的概要信息,包括GC、head configuration、generation-wise heap usage等
        -histo[:live]  打印堆的对象统计,包括对象数、内存大小等等
        -clstats  打印堆的类加载器统计信息。
        -F  强制。当pid没有反应时,将这个选项与jmap -dump或jmap -histo选项一起使用。在这种模式下不支持live子选项。
        -Jflag  将flag传递给运行jmap命令的Java虚拟机。
    
    description:
        jmap命令打印指定进程、核心文件或远程调试服务器的共享对象内存图或堆内存细节。
        如果指定的进程在64位Java虚拟机(JVM)上运行,那么你可能需要指定-J-d64选项,例如:jmap -J-d64 -heap pid。
    
    • 示例

      <!== 打印等待回收对象的信息 ==>

      $ jmap -finalizerinfo 30809
      Attaching to process ID 30809, please wait...
      Debugger attached successfully.
      Server compiler detected.
      JVM version is 25.251-b08
      Number of objects pending for finalization: 0
      

      <!== 打印堆概要信息 ==>

      $ jmap -heap 30809
      Attaching to process ID 30809, please wait...
      Debugger attached successfully.
      Server compiler detected.
      JVM version is 25.251-b08
      
      using thread-local object allocation.
      Parallel GC with 4 thread(s)   //GC方式
      
      Heap Configuration:   //堆内存初始化配置,对应jvm启动参数
         MinHeapFreeRatio         = 0
         MaxHeapFreeRatio         = 100
         MaxHeapSize              = 1073741824 (1024.0MB)
         NewSize                  = 357564416 (341.0MB)
         MaxNewSize               = 357564416 (341.0MB)
         OldSize                  = 716177408 (683.0MB)
         NewRatio                 = 2
         SurvivorRatio            = 8
         MetaspaceSize            = 268435456 (256.0MB)
         CompressedClassSpaceSize = 528482304 (504.0MB)
         MaxMetaspaceSize         = 536870912 (512.0MB)
         G1HeapRegionSize         = 0 (0.0MB)
      
      Heap Usage:  //堆内存使用情况
      PS Young Generation  //年轻代使用情况
      Eden Space:  //Eden区内存情况
         capacity = 353370112 (337.0MB)
         used     = 198190016 (189.00872802734375MB)
         free     = 155180096 (147.99127197265625MB)
         56.08567597250556% used
      From Space:  //其中一个Survivor区的内存情况
         capacity = 2097152 (2.0MB)
         used     = 1006928 (0.9602813720703125MB)
         free     = 1090224 (1.0397186279296875MB)
         48.014068603515625% used
      To Space:  //其中一个Survivor区的内存情况
         capacity = 2097152 (2.0MB)
         used     = 0 (0.0MB)
         free     = 2097152 (2.0MB)
         0.0% used
      PS Old Generation  //老年代内存情况
         capacity = 716177408 (683.0MB)
         used     = 62305128 (59.418800354003906MB)
         free     = 653872280 (623.5811996459961MB)
         8.699677943485199% used
      
      37015 interned Strings occupying 4020168 bytes.
      

      <!== 打印堆的对象统计 ==>

      $ jmap -F -histo 30809
      Attaching to process ID 30809, please wait...
      Debugger attached successfully.
      Server compiler detected.
      JVM version is 25.251-b08
      Iterating over heap. This may take a while...
      Object Histogram:
      
      num       #instances    #bytes  Class description
      --------------------------------------------------------------------------
      1:              183560  22797768        char[]
      2:              1395    4765360 long[]
      3:              15811   4545944 byte[]
      4:              181047  4345128 java.lang.String
      5:              41490   3651120 java.lang.reflect.Method
      6:              23943   3640280 int[]
      7:              107354  3435328 java.util.concurrent.ConcurrentHashMap$Node
      8:              49566   3015984 java.lang.Object[]
      9:              18664   2068768 java.lang.Class
      10:             34349   1373960 java.util.LinkedHashMap$Entry
      ...
      Total :         1176270 67035968
      Heap traversal took 47.908 seconds. 
      

      <!== 创建堆dump文件 ==>

      $ jmap -dump:format=b,file=/tmp/cus-operation-server.hprof 30809
      Attaching to process ID 30809, please wait...
      Debugger attached successfully.
      Server compiler detected.
      JVM version is 25.251-b08
      Dumping heap to /tmp/cus-operation-server.hprof ...
      Heap dump file created
      

      <!== 使用jhat命令分析堆dump文件 ==>

      $ jhat -J-Xmx2048m cus-operation-server.hprof 
      Reading from cus-operation-server.hprof...
      Dump file created Fri Apr 22 11:34:22 CST 2022
      Snapshot read, resolving...
      Resolving 5178821 objects...
      WARNING: Class c31ed980 not found, adding fake class!
      WARNING: Class c1feb088 not found, adding fake class!
      WARNING: Class c03bda70 not found, adding fake class!
      WARNING: Class c03bdaf0 not found, adding fake class!
      WARNING: Class c0847af0 not found, adding fake class!
      WARNING: Class c324d1b8 not found, adding fake class!
      WARNING: Class c03bc090 not found, adding fake class!
      WARNING: Class c03bc110 not found, adding fake class!
      WARNING: Class c03bc190 not found, adding fake class!
      WARNING:  Failed to resolve object id 0xc08089f0 for field clazz (signature L)
      WARNING:  Failed to resolve object id 0xc0808750 for field clazz (signature L)
      WARNING:  Failed to resolve object id 0xc08083c8 for field clazz (signature L)
      WARNING:  Failed to resolve object id 0xc0808128 for field clazz (signature L)
      WARNING:  Failed to resolve object id 0xc0807e90 for field clazz (signature L)
      Chasing references, expect 1035 dots...........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
      Eliminating duplicate references...........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
      Snapshot resolved.
      Started HTTP server on port 7000
      Server is ready. 
      

      登录web页面使用OQL进行查询分析

      主页面 oql查询页面
    oql语句帮助页面

    4、jstack

    打印 Java 进程、核心文件或远程调试服务器的 Java 线程堆栈跟踪。

    usage: jstack [ options ] pid
           jstack [ options ] executable core
           jstack [ options ] [ server-id@ ] remote-hostname-or-IP
        executable:生成可执行的核心转储文件
        core:打印内存映射的核心文件
        remote-hostname-or-IP:远程调试服务器主机名或IP地址
        server-id:当多个调试服务器在同一远程主机上运行时使用的可选唯一ID
    
    options:
        -F  当jstack [-l] pid没有反应时,强制进行堆栈转储
        -l  打印关于锁的额外信息
        -m  打印一个混合模式的堆栈跟踪,其中有Java和本地C/C++框架,该选项不适用于远程调试服务器
    
    description:
        jstack命令打印指定的Java进程、核心文件或远程调试服务器的Java线程的堆栈痕迹。对于每个Java框架,如果有的话,会打印完整的类名、方法名、字节码索引(BCI)和行号。当指定的进程在64位Java虚拟机上运行时,你可能需要指定-J-d64选项,例如:jstack -J-d64 -m pid。
        
    
    • 示例

      cpu异常问题排查步骤

      1. 使用top命令查看程序cpu占用率过高的线程

        $ top -Hp <pid>
        #结果保存截图
        
      2. 打印线程堆栈信息到文件

        $ jstack -l <pid> > <filename>
        
      3. 将步骤1中的占用cpu过高的TID转换成16进制

        $ printf "%x\n" TID
        
      4. 在堆栈文件中搜索对应TID

    5、jinfo

    生成配置信息,实时查看和调整虚拟机运行参数。

    usage: jinfo [ option ] pid
           jinfo [ option ] executable core
           jinfo [ option ] [ servier-id ] remote-hostname-or-IP
        executable:生成可执行的核心转储文件
        core:打印内存映射的核心文件
        remote-hostname-or-IP:远程调试服务器主机名或IP地址
        server-id:当多个调试服务器在同一远程主机上运行时使用的可选唯一ID
    
    
    options:
        <none>  打印命令行参数和系统属性名称-值对
        -flag name  打印指定命令行参数的名称和值
        -flag [+|-]name  启用或禁用指定的布尔值命令行参数
        -flag name=value  将指定的命令行参数设置为指定的值
        -flags  打印传递给JVM的命令行参数
        -sysprops  将Java系统属性打印为名称-值对
    
    description:
        jinfo命令打印指定Java进程或核心文件或远程调试服务器的Java配置信息。配置信息包括Java系统属性和JVM命令行标志。如果指定的进程在64位JVM上运行,那么您可能需要指定-J-d64选项,例如:jinfo -J-d64 -sysprops pid。
    
    • 示例

      <!== 打印命令行参数和系统属性 ==>

      $ jinfo 30809
      Attaching to process ID 30809, please wait...
      Debugger attached successfully.
      Server compiler detected.
      JVM version is 25.251-b08
      Java System Properties:
      
      com.sun.management.jmxremote.authenticate = false
      java.runtime.name = Java(TM) SE Runtime Environment
      java.vm.version = 25.251-b08
      sun.boot.library.path = /data/svr/jdk1.8.0_251/jre/lib/amd64
      java.protocol.handler.pkgs = org.springframework.boot.loader
      apollo.cluster = dev
      java.vendor.url = http://java.oracle.com/
      java.vm.vendor = Oracle Corporation
      path.separator = :
      java.rmi.server.randomIDs = true
      file.encoding.pkg = sun.io
      java.vm.name = Java HotSpot(TM) 64-Bit Server VM
      sun.os.patch.level = unknown
      sun.java.launcher = SUN_STANDARD
      user.country = US
      ...
      
      VM Flags:
      Non-default VM flags: -XX:AutoBoxCacheMax=20000 -XX:CICompilerCount=3 -XX:CompressedClassSpaceSize=528482304 -XX:GCLogFileSize=1048576 -XX:+HeapDumpOnOutOfMemoryError -XX:InitialHeapSize=1073741824 -XX:+ManagementServer -XX:MaxHeapSize=1073741824 -XX:MaxMetaspaceSize=536870912 -XX:MaxNewSize=357564416 -XX:MetaspaceSize=268435456 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=357564416 -XX:NumberOfGCLogFiles=10 -XX:OldSize=716177408 -XX:+PrintGC -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseGCLogFileRotation -XX:+UseParallelGC 
      Command line:  -Xms1024m -Xmx1024m -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=512M -XX:+HeapDumpOnOutOfMemoryError -XX:AutoBoxCacheMax=20000 -Xloggc:/dev/shm/gc-fbg-il8n-server.log -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=1M -Djava.rmi.server.hostname=10.81.48.30 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=50606 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dapp.name=fbg-il8n-server -Dapp.repo=/data/local/apps/fbg-il8n-server/lib -Dapp.home=/data/local/apps/fbg-il8n-server -Dbasedir=/data/local/apps/fbg-il8n-server
      

      <!== 打印指定命令行参数信息 ==>

      #需要以程序运行用户执行
      $ jinfo -flag MaxMetaspaceSize 30809
      -XX:MaxMetaspaceSize=536870912
      

      <!== 动态修改命令行参数 ==>

      $ jinfo -flag MaxHeapFreeRatio=65 30809
      $ jinfo -flags 30809
      Attaching to process ID 30809, please wait...
      Debugger attached successfully.
      Server compiler detected.
      JVM version is 25.251-b08
      Non-default VM flags: -XX:AutoBoxCacheMax=20000 -XX:CICompilerCount=3 -XX:CompressedClassSpaceSize=528482304 -XX:GCLogFileSize=1048576 -XX:+HeapDumpOnOutOfMemoryError -XX:InitialHeapSize=1073741824 -XX:+ManagementServer -XX:MaxHeapFreeRatio=65 -XX:MaxHeapSize=1073741824 -XX:MaxMetaspaceSize=536870912 -XX:MaxNewSize=357564416 -XX:MetaspaceSize=268435456 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=357564416 -XX:NumberOfGCLogFiles=10 -XX:OldSize=716177408 -XX:+PrintGC -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseGCLogFileRotation -XX:+UseParallelGC 
      Command line:  -Xms1024m -Xmx1024m -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=512M -XX:+HeapDumpOnOutOfMemoryError -XX:AutoBoxCacheMax=20000 -Xloggc:/dev/shm/gc-fbg-il8n-server.log -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=1M -Djava.rmi.server.hostname=10.81.48.30 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=50606 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dapp.name=fbg-il8n-server -Dapp.repo=/data/local/apps/fbg-il8n-server/lib -Dapp.home=/data/local/apps/fbg-il8n-server -Dbasedir=/data/local/apps/fbg-il8n-server 
      
      #支持动态修改的参数
      $ java -XX:+PrintFlagsInitial | grep manageable
           intx CMSAbortablePrecleanWaitMillis            = 100                                 {manageable}
           intx CMSTriggerInterval                        = -1                                  {manageable}
           intx CMSWaitDuration                           = 2000                                {manageable}
           bool HeapDumpAfterFullGC                       = false                               {manageable}
           bool HeapDumpBeforeFullGC                      = false                               {manageable}
           bool HeapDumpOnOutOfMemoryError                = false                               {manageable}
          ccstr HeapDumpPath                              =                                     {manageable}
          uintx MaxHeapFreeRatio                          = 70                                  {manageable}
          uintx MinHeapFreeRatio                          = 40                                  {manageable}
           bool PrintClassHistogram                       = false                               {manageable}
           bool PrintClassHistogramAfterFullGC            = false                               {manageable}
           bool PrintClassHistogramBeforeFullGC           = false                               {manageable}
           bool PrintConcurrentLocks                      = false                               {manageable}
           bool PrintGC                                   = false                               {manageable}
           bool PrintGCDateStamps                         = false                               {manageable}
           bool PrintGCDetails                            = false                               {manageable}
           bool PrintGCID                                 = false                               {manageable}
           bool PrintGCTimeStamps                         = false                               {manageable}
      

    二、常见JVM内存错误问题排查

    1、Java heap space

    当堆内存(Heap Space)没有足够空间存放新创建的对象时,就会抛出java.lang.OutOfMemoryError: Java heap space 错误。

    • 原因分析

      1. 请求创建一个超大对象

      2. 超出预期的访问量/数据量,通常是上游系统请求流量飙升,常见于各类促销/秒杀活动,可以结合业务流量指标排查是否有尖状峰值。

      3. 过度使用终结器(Finalizer),该对象没有立即被GC.

      4. 内存泄漏(Memory Leak),大量对象引用没有释放,JVM无法对其自动回收,常见于使用了File等资源没有回收。

    • 解决方案

      首先使用jmap -dump:format=b,file=FILE_WITH_PATH PID 命令生成dump文件已变后续分析, 再通过-Xmx参数调高 JVM 堆内存空间重启服务(临时解决)。如果是超大对象,可以检查其合理性,比如是否一次性查询了数据库全部结果,而没有做结果数限制。如果是业务峰值压力,可以考虑添加机器资源,或者做限流降级。如果是内存泄漏,需要找到持有的对象,修改代码设计,比如关闭没有释放的连接。

    2、GC overhead limit exceeded

    当Java进程花费98%以上的时间执行GC,但只恢复了不到2%的内存,且该动作连续重复了5次,就会抛出java.lang.OutOfMemoryError: GC overhead limit exceeded 错误。简单地说,就是应用程序已经基本耗尽了所有可用内存,GC也无法回收。

    此类问题的原因与解决方案跟 Java heap space 非常类似,可以参考上文。

    3、Permgen space

    java.lang.OutOfMemoryError: Permgen space该错误表示永久代(Permanent Generation)已用满。

    • 原因分析

      通常是因为加载的class数目太多或体积太大。PermGen的使用量与加载到内存的class的数量/大小成正相关。

    • 解决方案

      根据 Permgen space 报错的时机,可以采用不同的解决方案:

      1. 程序启动报错,修改-XX:MaxPermSize启动参数,调大永久代空间。

      2. 应用重新部署时报错,很可能是没有应用没有重启,导致加载了多份 class 信息,只需重启 JVM 即可解决。

      3. 运行时报错,应用程序可能会动态创建大量class,而这些class的生命周期很短暂,但是JVM默认不会卸载class,可以设置-XX:+CMSClassUnloadingEnabled-XX:+UseConcMarkSweepGC这两个参数允许JVM卸载class。

      上述方法无法解决,可以通过jmap -dump:format=b,file=FILE_WITH_PATH PID命令生成dump文件,然后利用Eclipse MAT软件功能逐一分析开销最大的classloader和重复class。

    4、Metaspace

    JDK 1.8使用Metaspace(元空间)替换了永久代(Permanent Generation),java.lang.OutOfMemoryError: Metaspace该错误表示Metaspace已被用满。

    此类问题的原因与解决方法跟Permgen space非常类似,可以参考上文。需要特别注意的是调整Metaspace空间大小的启动参数为 -XX:MaxMetaspaceSize

    5、Unable to create new native thread

    每个Java线程都需要占用一定的内存空间,当JVM向底层操作系统请求创建一个新的native线程时,如果没有足够的资源分配就会报此类错误java.lang.OutOfMemoryError: Unable to create new native thread

    • 原因分析

      1. 线程数超过操作系统最大线程数ulimit限制。

      2. 线程数超过kernel.pid_max(只能重启)。

      3. 本机内存不足。

    • 解决方案

      • 升级服务器内存资源

      • 降低 Java Heap Space 大小

      • 修复应用程序的线程泄漏问题

      • 限制线程池大小

      • 使用-Xss参数减少线程栈的大小

      • 调高OS层面的线程最大数:使用ulimit -u xxx 命令调整最大线程数限制。

    6、Out of swap space?

    java.lang.OutOfMemoryError: Out of swap space?该错误表示所有可用的虚拟内存已被耗尽。虚拟内存(Virtual Memory)由物理内存(Physical Memory)和交换空间(Swap Space)两部分组成。当运行时程序请求的虚拟内存溢出时就会报 Out of swap space? 错误。

    • 原因分析

      1. 主机虚拟内存耗尽

      2. 应用程序的本地内存泄漏(native leak)

    • 解决方案

      升级服务器内存资源

    7、Direct buffer memory

    DirectByteBuffer顾名思义直接缓冲,我们可以使用它进行堆外内存的分配/使用/回收。DirectByteBuffer晋升到老年代,必须要等到full gc 才有可能被回收。当DirectByteBuffer使用较多且存活时间过长的情况时,则可能造成堆外内存OOM出现java.lang.OutOfMemoryError: Direct buffer memory错误

    • 原因分析

      1. 通过 ByteBuffer.allocateDirect 方法使用Direct ByteBuffer,该方法是分配堆外内存,不属于GC管辖范围,由于不需要内存拷贝所以速度相对较快。但如果不断分配堆外内存,堆内存很少使用,那么JVM就不需要进行GC,DirectByteBuffer对象们就不会被回收。这个时候堆内存充足,但堆外内存可能已经耗尽。

      2. Direct ByteBuffer使用值超过最大上限

    • 解决方案

      1. 通过启动参数-XX:MaxDirectMemorySize调整 Direct ByteBuffer 的上限值。

      2. 去掉启动参数-XX:+DisableExplicitGC ,该参数会使 System.gc() 失效。

      3. 检查堆外内存使用代码,确认是否存在内存泄漏;或者通过反射调用 sun.misc.Cleaner 的 clean() 方法来主动释放被 Direct ByteBuffer 持有的内存空间。

    相关文章

      网友评论

          本文标题:JVM

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