zoukankan      html  css  js  c++  java
  • Heap堆分析(堆转储、堆分析)

    一、堆直方图

      减少内存使用时一个重要目标,在堆分析上最简单的方法是利用堆直方图。通过堆直方图我们可以快速看到应用内的对象数目,同时不需要进行完整的堆转储(因为堆转储需要一段时间来分析,而且会消耗大量磁盘空间)。

    直方图擅长识别由分配了一两个特定类的过多实例所引发的问题。例如应用中的内存压力是由一些特定的对象类型引起的,利用堆直方图可以很快就能看出端倪。

    1.1、通过jcmd获得

    堆直方图可以通过jcmd命令获得:

    [ciadmin@2-103test_app ~]$ jcmd 26964 GC.class_histogram | more
    26964:
    
     num     #instances         #bytes  class name
    ----------------------------------------------
       1:         91488       21270064  [C
       2:          9058       18963152  [B
       3:         80620        2579840  java.util.concurrent.ConcurrentHashMap$Node
       4:         24081        2119128  java.lang.reflect.Method
       5:         86860        2084640  java.lang.String
       6:         13013        1444264  java.lang.Class
       7:         24376        1170048  org.aspectj.weaver.reflect.ShadowMatchImpl
       8:         26822        1072880  java.util.LinkedHashMap$Entry
       9:           553         921168  [Ljava.util.concurrent.ConcurrentHashMap$Node;
      10:         15903         890568  java.util.LinkedHashMap
      11:         12092         847832  [Ljava.util.HashMap$Node;
      12:           307         829712  [J
      13:         24376         780032  org.aspectj.weaver.patterns.ExposedState
      14:         12621         718696  [Ljava.lang.Object;
      15:          5433         686400  [I
      16:         36341         581456  java.lang.Object
      17:         17746         567872  java.util.HashMap$Node
      18:          1267         476392  java.lang.Thread
      19:         13207         422624  java.lang.ThreadLocal$ThreadLocalMap$Entry
      20:          2516         270336  [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;

    说明:

    1、字段说明

    • [C:字符数组
    • [B:字节数组
    • [Ljava.lang.Object:Object数组

    2、GC.class_histogram输出的仅包含活跃对象

    1.2、通过jmap获得

    命令为:jmap -histo process_id

    jmap的输出中包含会被回收的对象(死对象)。要在看到直方图之前强制执行一次Full GC,可以转而运行下面的命令:

    如下,在命令行中增加:live参数后,输出的直方图是Full GC之后的数据

    [ciadmin@2-103test_app ~]$ jmap -histo:live 26964 | more
    
     num     #instances         #bytes  class name
    ----------------------------------------------
       1:         91488       21270064  [C
       2:          9058       18963152  [B
       3:         80620        2579840  java.util.concurrent.ConcurrentHashMap$Node
       4:         24081        2119128  java.lang.reflect.Method
       5:         86860        2084640  java.lang.String
       6:         13013        1444264  java.lang.Class
       7:         24376        1170048  org.aspectj.weaver.reflect.ShadowMatchImpl
       8:         26822        1072880  java.util.LinkedHashMap$Entry
       9:           553         921168  [Ljava.util.concurrent.ConcurrentHashMap$Node;
      10:         15903         890568  java.util.LinkedHashMap
      11:         12092         847832  [Ljava.util.HashMap$Node;
      12:           307         829712  [J
      13:         24376         780032  org.aspectj.weaver.patterns.ExposedState
      14:         12621         718696  [Ljava.lang.Object;
      15:          5433         686400  [I
      16:         36341         581456  java.lang.Object
      17:         17749         567968  java.util.HashMap$Node
      18:          1267         476392  java.lang.Thread
      19:         13207         422624  java.lang.ThreadLocal$ThreadLocalMap$Entry
      20:          2516         270336  [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;
      21:          8056         257792  java.util.LinkedList
      22:         11664         247432  [Ljava.lang.Class;
      23:          4397         187064  [Ljava.lang.String;
      24:          1945         186720  org.springframework.beans.GenericTypeAwarePropertyDescriptor
      25:          5631         180192  java.lang.ref.WeakReference
      26:          3630         174240  java.util.HashMap

    直方图非常小,但获取直方图也需要几秒时间。性能测试时需要注意它。

    二、堆转储

    直方图擅长识别由分配了一两个特定类的过多实例所引发的问题,但是要深度分析,就需要堆转储了。

    2.1、使用jcmd进行堆转储

    [ciadmin@2-103test_app pos-gateway-cloud]$ jcmd 26964 GC.heap_dump /home/ciadmin/pos-gateway-cloud/heap_dump.hprof
    26964:
    Heap dump file created

    2.2、使用jmap进行堆转储

    [ciadmin@2-103test_app pos-gateway-cloud]$ jmap -dump:live,file=/home/ciadmin/pos-gateway-cloud/heap_dump2.hprof 26964
    Dumping heap to /home/ciadmin/pos-gateway-cloud/heap_dump2.hprof ...
    Heap dump file created

    jmap中包含live选项,会在堆转储前执行一次Full GC;jcmd默认就会这么做。如果因为某些原因,不希望包含其他对象(即死对象),可以在jcmd命令的最后加上-all。

    2.3、自动堆转储

    OutOfMemoryError是不可预料的,我们很难确定应该何时获得堆转储。有几个JVM标志可以起到帮助。

    -XX:+HeapDumpOnOutOfMemoryError该标志默认为false,打开该标志,JVM会在抛出OutOfMemoryError时创建堆转储。

    -XX:HeapDumpPath=<path>该标志知道了堆转储将被写入的位置,默认为当前工作目录下生产java_pid<pid>.hprof文件。

    -XX:+HeapDumpAfterFullGC 这会在运行一次Full GC后生成一个堆转储文件。

    -XX:+HeapDumpBeforeFullGC 这会在运行一次Full GC之前生成一个堆转储文件。

    有的情况下,(入帮,因为执行了多次Full GC)会生成多个堆转储文件,这时JVM会在堆转储文件的名字上附加一个序号。

    这两条命令都会在指定目录下创建一个命名为*.hprof的文件。生成之后,有很多工具可以打开该文件。以下是三个最常见的工具。

    三、堆转储文件分析工具

    jhat

      这是最原始的分析工具,它会读取堆转储文件,并运行一个小型的HTTP服务器,该服务器运行你通过一系列网易链接查看堆转储信息。

    [ciadmin@2-103test_app pos-gateway-cloud]$ jhat heap_dump.hprof 
    Reading from heap_dump.hprof...
    Dump file created Mon Mar 05 18:33:10 CST 2018
    Snapshot read, resolving...
    Resolving 751016 objects...
    Chasing references, expect 150 dots......................................................................................................................................................
    Eliminating duplicate references......................................................................................................................................................
    Snapshot resolved.
    Started HTTP server on port 7000
    Server is ready.

    找一台带浏览器的机器访问它,http://ip:7000

    更多信息见《九、jdk工具之jhat命令(Java Heap Analyse Tool)、jhat之一:对dump的结果在浏览器上展示

    jvisualvm

    jvisualvm的监视(Monitor) 选项卡可以从一个运行中的程序获得堆转储文件,也可以打开之前生成堆转储文件。

    更多信息见《八、jdk工具之JvisualVM、JvisualVM之一--(visualVM介绍及性能分析示例)

    mat

    开源的EclipseLink内存分析器工具(EclipseLink Memory Analyzer Tool,mat)可以加载一个或多个堆转储文件并执行分析。它可以生成报告,向我们建议可能存在问题的地方,也可以用于流量堆,并对堆执行类SQL的查询。

    特别指出的是:mat内置一功能:如果打开了两个堆转储文件,mat有一个选项用来计算两个堆中的直方图之间的差别。

    更多信息见《mat之一--eclipse安装Memory Analyzer

    对堆的第一遍分析通常涉及保留内存。一个对象的保留内存,是指回收该对象可以释放出的内存量。

    关于保留内存相关知识见《GC之二--GC是如何回收时的判断依据、shallow(浅) size、retained(保留) size、Deep(深)size

    四、内存溢出错误

    在下面情况下,jvm会抛出内存溢出错误(OutOfMemeoryError):

    • JVM没有原生内存可用;
    • 永久代(在java7和更早的版本中)或元空间(java8)内存不足;
    • java堆本身内存不足--对于给定的堆空间而言,应用中活跃对象太多;
    • JVM执行GC耗时太多;

    1、原生内存不足

    其原因与堆根本无关。在32位的JVM中,一个进程的最大内存是4GB,如果指定一个非常大的堆大小,比如说3.8GB,使应用的大小很接近4GB的限制,这很危险。

    2、永久代或元空间内存不足

    首先与堆无关,其根源可能有两种情况:

    • 第一种情况是应用使用的类太多,超出了永久代的默认容纳范围;解决方案:增加永久代的大小
    • 第二种情况相对来说有点棘手:它涉及类加载器的内存泄漏。这种情况经常出现于Java EE应用服务器中。类加载导致内存溢出可以通过堆转储分析,在直方图中,找到ClassLoader类的所有实例,然后跟踪他们的GC根,看哪些对象还保留了对它们的引用。

    示例:

    3、堆内存不足

    当确实是堆内存本身不足时,错误信息会这样:

    OutOfMemoryError:Java heap space

    可能的原因有:

    1、活跃对象数目在为其配置的堆空间中已经装不下了。

    2、也可能是应用存在内存泄漏:它持续分配新对象,却没有让其他对象退出作用域。

    不管哪种情况,要找出哪些对象消耗的内存最多,堆转储分析都是必要的;

    4、达到GC的开销限制

    JVM抛出OutOfMemoryError的最后一种情况是JVM任务在执行GC上花费了太多时间:

    OutOfMemoryError:GC overhead limit exceeded

    当满足下列所有条件时就会抛出该错误:

    1、花在Full GC的时间超出了-XX:GCTimeLimit=N标志指定的值。默认为98

    2、一次Full GC回收内存量少于-XX:GCHeapFreeLimit=N标志指定的值。默认值为2(2%)

    3、上面两个条件连续5次Full GC都成立(这个值无法调整)

    4、-XX:+UseGCOverhead-Limit标志为true(默认也为true)

    这四个条件必须都满足。一般来说,连续5次Full GC以上,不一定会抛异常。即使98%时间在Full GC上,但每次GC期间释放的堆空间会超过2%,这种情况下可以增加-XX:GCHeapFreeLimit的值。

    还请注意,如果前两个条件连续4次Full GC周期都成立,作为释放内存的最后一搏,JVM中所有的软引用都会在第五次Full GC之前被释放。这往往会防止该错误,因为第五次Full GC很可能会释放超过2%的堆内存(假设该应用使用了软引用)。

  • 相关阅读:
    nginx 特定目录禁止php执行
    linux awk命令详解
    漫谈大型网站架构
    ThinkPHP 自动验证实例
    使用jquery时一些小技巧的总结
    fputcsv 导出CSV、Excel DownLoad
    文件操作总结
    rc.local 开机自启脚本无法启动
    Windows pycharm Terminal使用Anaconda 的Prompt
    解决hash冲突方法
  • 原文地址:https://www.cnblogs.com/duanxz/p/8510623.html
Copyright © 2011-2022 走看看