一、堆直方图

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

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

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%的堆内存(假设该应用使用了软引用)。

Heap堆分析(堆转储、堆分析)的更多相关文章

  1. 使用 Eclipse Memory Analyzer 进行堆转储文件分析

    Eclipse Memory Analyzer(MAT)是著名的跨平台集成开发环境 Eclipse Galileo 版本的 33 个组成项目中之一,它是一个功能丰富的 JAVA 堆转储文件分析工具,可 ...

  2. mat 使用 分析 oom 使用 Eclipse Memory Analyzer 进行堆转储文件分析

    概述 对于大型 JAVA 应用程序来说,再精细的测试也难以堵住所有的漏洞,即便我们在测试阶段进行了大量卓有成效的工作,很多问题还是会在生产环境下暴露出来,并且很难在测试环境中进行重现.JVM 能够记录 ...

  3. [Android Memory] 使用 Eclipse Memory Analyzer 进行堆转储文件分析

    转载地址:http://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-ma/index.html Eclipse Memory Analyzer ...

  4. 源码分析:Java堆的创建

    虚拟机在内存中申请一片区域,由虚拟机自动管理,用来满足应用程序对象分配的空间需求,即堆空间. 由于程序运行的局部特性,程序创建的大多数对象都具有非常短的生命周期,而程序也会创建一些生命周期特别长的对象 ...

  5. C#中堆和栈的区别分析(有待更新总结)

    转载:http://blog.csdn.net/zevin/article/details/5721495 一.预备知识-程序的内存分配 一个由C/C++编译的程序占用的内存分为以下几个部分 1.栈区 ...

  6. Fortify Audit Workbench 笔记 Privacy Violation: Heap Inspection 隐私泄露(堆检查)

    Privacy Violation: Heap Inspection 隐私泄露(堆检查) Abstract 将敏感数据存储在 String 对象中使系统无法从内存中可靠地清除数据. Explanati ...

  7. 堆(Heap)和二叉堆(Binary heap)

    堆(Heap) The operations commonly performed with a heap are: create-heap: create an empty heap heapify ...

  8. 干货:JVM 堆内存和非堆内存

    堆和非堆内存 按照官方的说法:"Java 虚拟机具有一个堆(Heap),堆是运行时数据区域,所有类实例和数组的内存均从此处分配.堆是在 Java 虚拟机启动时创建的."" ...

  9. 堆排序(大顶堆、小顶堆)----C语言

    堆排序 之前的随笔写了栈(顺序栈.链式栈).队列(循环队列.链式队列).链表.二叉树,这次随笔来写堆 1.什么是堆? 堆是一种非线性结构,(本篇随笔主要分析堆的数组实现)可以把堆看作一个数组,也可以被 ...

  10. 结构之美——优先队列基本结构(四)——二叉堆、d堆、左式堆、斜堆

    实现优先队列结构主要是通过堆完成,主要有:二叉堆.d堆.左式堆.斜堆.二项堆.斐波那契堆.pairing 堆等. 1. 二叉堆 1.1. 定义 完全二叉树,根最小. 存储时使用层序. 1.2. 操作 ...

随机推荐

  1. 51Nod 1084:矩阵取数问题 V2(多维DP)

    1084 矩阵取数问题 V2  基准时间限制:2 秒 空间限制:131072 KB 分值: 80 难度:5级算法题  收藏  关注 一个M*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励 ...

  2. SSAS aggregation 的作用及其使用

    作用: 聚合是为了解决查询在运行时的效率低下,在数据立方体部署的时候进行聚合,实际上是对数据立方体的预处理,方便以后查询.如若在部署时未进行聚合,则在以后每次查询时实际上都会进行一次集合的操作,等待结 ...

  3. 不输入密码执行sudo 命令

    命令行执行的crontab 命令,但是需要包含sudo 才可以执行的命令,怎么办呢?见下: leo@leo-Ubuntu:/etc$ visudovisudo: /etc/sudoers: 权限不够v ...

  4. Redis源码剖析和注释(七)--- 快速列表(quicklist)

    Redis 快速列表(quicklist)1. 介绍quicklist结构是在redis 3.2版本中新加的数据结构,用在列表的底层实现. 通过列表键查看一下:redis 列表键命令详解 127.0. ...

  5. WikiBooks/Cg Programming

    https://en.wikibooks.org/wiki/Cg_Programming Basics Minimal Shader(about shaders, materials, and gam ...

  6. Web-Business-Application-Solution

    项目地址 :  https://github.com/kelin-xycs/Web-Business-Application-Solution Web-Business-Application-Sol ...

  7. Percona XtraDB Cluster高可用与状态快照传输(PXC 5.7 )

    Percona XtraDB Cluster(下称PXC)高可用集群支持任意节点在运行期间的重启,升级或者意外宕机,即它解决了单点故障问题.那在这个意外宕机或者重启期间,该节点丢失的数据如何再次进行同 ...

  8. MYSQL 中的 int(11) 到底代表什么意思?

    各 INT 类型无符号最大值用单位表示: INT 类型 无符号最大值用单位表示 TINYINT 255 SMALLINT 65535 MEDIUMINT 1677 万 INT 42 亿 BIGINT ...

  9. spring boot 学习资料

    spring boot 学习资料: 学习资料 网址 Spring Boot Cookbook-极客学院 http://wiki.jikexueyuan.com/project/spring-boot- ...

  10. gaea-editor 知识点

    github 地址:https://github.com/ascoders/gaea-editor