java堆简单介绍

Posted 不忘初心2021

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java堆简单介绍相关的知识,希望对你有一定的参考价值。

java对象实例是放置堆上,但不是说所有的对象实例都在对上,可能有些对象实例位于本地方法区

 下面说说堆的特点

 堆是属于java虚拟机中内存最大的一部分

堆是jvm中所有线程可以共享的

垃圾收集器管理的主要区域来源于java堆

 java堆可以细分为新生代和老年代

java堆在物理存储上是不连续的,但是逻辑上是连续的,对应的大小通过-Xms和-Xmx调节

堆中的实例对象,并不是方法结束后就直接被回收了,直接回收的话,jvm压力很大的,所以是异步回收

当堆内存不够了,就会抛出OutOfMemoryError异常

下面使用实际代码测试结果

测试代码

package com.java.test;

import java.util.ArrayList;

/**
 * @Description:
 * @Author: qiuxie
 * @Create: 2023/5/7 23:52
 */
public class JvmTest 

    /**
     * jvm堆内存相关
     * -Xmx20M -Xms5M
     * @param args
     */
    public static void main(String[] args) 
        //创建数据分配内存
        //int[] a=new int[3*1024*1024];
        //a[0]=12345;
        System.out.print("Xmx=");
        System.out.println(Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M");
        System.out.print("free mem=");
        System.out.println(Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M");
        System.out.print("total mem=");
        System.out.println(Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");
    


  

设置的堆内存大小
-Xmx20M -Xms5M

 

 不同的jdk版本中,堆中的包含也是不一样的

在jdk 1.7中

报错部分可忽略

 

 而在jdk 1.8中

只有青年代和老年代了

-XX:+PrintGCDetails

  

 

 jdk 11的堆空间信息

 

 相比较jdk 1.8,少了很多

 以上就是关于java堆的简单介绍

 

Java堆分析器 - Eclipse Memory Analyzer Tool(MAT)

       Java堆(heanp dump)文件是一个纯二进制文件,咱们用肉眼去看肯定是不现实的。所以咱们得借助特定的堆分析器来对dump文件做相应的分析。这里我们选用Eclipse Memory Analyzer(MAT)来作为heap dump文件的分析工具。接下来咱们对MAT工具做一个简单的介绍。方便咱们后续分析Java堆(heap dump)

       Eclipse Memory Analyzer Tool(简称MAT)是一个非常强大的的内存分析工具,可以帮助我们分析堆内存,找到内存泄露的地方,减少内存消耗。MAT除了可以作为Eclipse的插件使用。官方也提供了独立的安装版本,我们用IDEA用的比较多,所以使用独立的安装版本,直接进入下载页面 https://www.eclipse.org/mat/downloads.php ,下载适合自己的版本。为了方便大家我这里提前下载了一份Window 64位的安装包 https://download.csdn.net/download/wuyuxing24/12302636

       在介绍MAT工具之前我们先介绍几个常用术语。在MAT工具中这几个术语经常出现:

  • Shallow Size: 对象自身占用的内存大小。
  • Retained Size: 对象本身的Shallow Size + 该对象直接或间接引用到的对象的Shallow Size。(也就是说Retained Size就是该对象被GC之后所能回收的内存的总和)
  • GC Roots: 是一组必须活跃的引用。GC会收集那些不是GC Roots且没有被GC roots引用的对象。基本思路就是通过一系列名为GC Roots 的对象作为起始点开始向下搜索。如果一个对象到GC Roots没有任何引用链相连时,则说明此对象不可用。换句话说就是能被遍历到的(可到达的)对象就被判定为存活,没有被遍历到的就自然被判定为死亡。

哪些对象可以作为Gc Roots的对象:

  • 虚拟机(栈帧中的本地变量表)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI(即一般说的native方法)中引用的对象

一 MAT结构介绍

1.1 区域一:Inspector区域

       用于展示指定对象的详细信息(选定一个对象的时候),从上到下依次是:内存地址、加载器名称、包名、对象名称、对象所属类的父类、对象所属类的加载器对象对象的堆内存大小(shallow size)、保留大小(retained size)、gc roots信息。

1.2 区域二:Inspector区域下方的区域

       展示对象的一些属性信息、类层级信息。

1.3 区域三:常用工具栏区域

       常用工具按钮从左到右依次是:概览(Overview)、类直方图(Histogram)、支配树(Dominator Tree)、OQL查询、线程视图、报告相关、详细功能(提供了一些更细致的分析能力)。

1.4 区域四:功能视图区域

       根据选择的功能不同,该区域显示对应功能的详细信息。比如我们想看Overview信息(点击区域三常用工具栏的第一个按钮)该区域就会展示heap dump Overview对应的信息。

二 MAT视图,功能

2.1 Overview视图

进入Overview视图

  • 使用MAT打开一个heap dump文件,解析完成后,默认就会进入Overview视图页面。
  • 工具栏中点击Overview按钮(区域三常用工具栏的第一个按钮)展示Overview对应的信息。

    Overview视图使用

       Overview视图界面包括两个部分:一个是对heap dump文件的一个大致的分析,包括占用内存大小,类个数,对象个数,类加载器个数,及用饼图的方式展示对象retained size信息、另一个是提供了一些常用的入口,包括视图入口(Actions)、常用的分析报告入口(Reports)、MAT使用教程入口(Step By Step)]。

       关于Overview视图区域,我们得关注点应该放在饼图上(根据retained size 对所有对象做排序,使用拼图演示结果)。我们可以方便的看到哪些对象的ratained size比较大(如果某个对象的retained size特别大。我们就要特别小心了,可能有问题了)。当我们鼠标点击每个饼图区域(对象)的时候,会弹出一个菜单,我们还可以查看相应对象的详细信息。这个菜单包含的额内容有:

  • List objects:
  • with ontgoing references:查看当前对象持有的外部对象引用。
  • with incoming references:查看当前对象被那些外部对象所引用。
  • Show objects by class
  • with ontgoing references: 查看这个对象类型持有的外部对象引用
  • with ontgoing references: 查看这个对象类型被哪些外部对象引用
  • Path To GC Roots: 从对象到GC Roots的路径。这个路径解释了为什么当前对象还能存活,对分析内存泄露很有帮助。(这个查询只能针对单个对象使用)。这里面可能需要咱们对引用有一定的了解,咱们也做一个简单的介绍。

       强引用(strong reference): 大家平常写代码的引用都是这种类型的引用,它可以防止引用的对象被垃圾回收。软引用(soft reference): 内存溢出之前进行回收,GC时内存不足时回收,如果内存足够就不回收。弱引用(weak reference): 每次GC时回收,无论内存是否足够。虚引用(phantom reference):每次垃圾回收时都会被回收,主要用于监测对象是否已经从内存中删除。

  • with all references: 从GC Roots节点到该对象的引用路径,包含所有引用类型。
  • exclude weak references:从该对象到GC Roots节点的最短引用路径,去除弱引用。
  • exclude soft references:从该对象到GC Roots节点的最短引用路径,去除软引用。
  • exclude pahantorn references:从该对象到GC Roots节点的最短引用路径,去除虚引用。
  • exclude weak/soft references:从该对象到GC Roots节点的最短引用路径,去除弱引用,软引用。
  • exclude phantom/soft references:从该对象到GC Roots节点的最短引用路径,去除虚引用,软引用。
  • exclude phantom/weak references:从该对象到GC Roots节点的最短引用路径,去除虚引用,弱引用。
  • exclude all phantom/weak/soft etc. references:从该对象到GC Roots节点的最短引用路径,去除虚引用,弱引用,软引用。
  • exclude custom references:从该对象到GC Roots节点的最短引用路径,去除自定义引用。
  • Merge Shortest Paths to GC Roots: 从GC Roots到对象的共同路径。

  • Java Basics:

  • References: 显示引用和对象的统计信息,列出类加载器,包括定义的类
  • Class Loader Explorer: 列出选定对象的类装载器,包括其定义的类 。
  • Customized Retained Set: 计算选中对象的保留堆,排除指定的引用。
  • Group By Value: 按对象的字符串表示形式对其进行分组。
  • Open In Domainator Tree: 对选中对象生成支配树。
  • Show As Histogram: 展示任意对象的直方图。
  • leak Identification:内存泄露识别。
  • Export Snapshot: 导出快照信息。
  • Immediate Dominators: 查看某个对象的dominator
  • Show Retained Set: 计算一个对象的保留堆大小
  • Copy: 拷贝一些属性。
  • Search Queries: 搜索查询相关。

2.2 Histogram视图

进入Histogram视图

  • 工具栏中点击Histogram按钮(区域三常用工具栏的第二个按钮)。
  • Overview页面的Actions部分有进入Histogram视图的快捷方式。

    Histogram视图使用

       Histogram视图从Class类的维度展示每个Class类的实例存在的个数、 占用的Shallow内存和Retained内存大小。

       咱们从Histogram视图可以看出,哪个Class类的对象实例数量比较多,以及占用的内存比较大,不过,多数情况下,在Histogram视图看到实例对象数量比较多的类都是一些基础类型,如char[](因为其构成了String)、String、byte[],所以仅从这些是无法判断出具体导致内存泄露的类或者方法的,可以使用 List objects 或 Merge Shortest Paths to GC roots 等功能继续钻取数据。如果Histogram视图展示的数量多的实例对象不是基础类型,是有嫌疑的某个类,如项目代码中的bean类型,那么就要重点关注了。

       如果存在内存溢出,时间久了溢出类的实例数量或者内存占比会越来越多,排名也越来越靠前的。可以点击工具类上的对比图标进行对比,通过多次对比不同时间点下的直方图对比就很容易把溢出的类找出来。

       每个类的详细信息(鼠标右键某个类的时候弹出框)

  • List objects:
  • with ontgoing references:查看当前类的所有对象,并且列出这些对象持有的外部对象引用。
  • with incoming references:查看当前类的所有对象,并且列出这些对象被那些外部对象所引用。
  • Show objects by class
  • with ontgoing references: 查看这个对象类型持有的外部对象引用
  • with ontgoing references: 查看这个对象类型被哪些外部对象引用
  • Merge Shortest Paths to GC Roots: 从GC Roots到对象的共同路径。

  • Java Basics:

  • References: 显示引用和对象的统计信息,列出类加载器,包括定义的类
  • Class Loader Explorer: 列出选定对象的类装载器,包括其定义的类 。
  • Customized Retained Set: 计算选中对象的保留堆,排除指定的引用。
  • Group By Value: 按对象的字符串表示形式对其进行分组。
  • Open In Domainator Tree: 对选中对象生成支配树。
  • Show As Histogram: 展示任意对象的直方图。
  • Java Collections
  • Array Fill Ratio: 输出数组中,非基本类型、非null对象个数占数组总长度的比例。
  • Arrays Grouped By Size: 显示数组的直方图,按大小分组。
  • leak Identification:内存泄露识别。
  • Export Snapshot: 导出快照信息。
  • Immediate Dominators: 查看某个对象的dominator
  • Show Retained Set: 计算一个对象的保留堆大小
  • Copy: 拷贝一些属性。
  • Search Queries: 搜索查询相关。
  • Calculate Minimum Retained Size(quick approx.): 计算最小的Ratined Size。
  • Calculate Precise Ratined Size: 精确计算Ratined Size。

2.3 Dominator Tree视图


进入Dominator Tree视图

  • 工具栏中点击Dominator Tree按钮(区域三常用工具栏的第三个按钮)。
  • Overview页面的Actions部分有进入Dominator Tree视图的快捷方式。

Dominator Tree视图使用

       Dominator Tree视图中列出了每个对象(Object Instance)与其引用关系的树状结构,同时包含了占用内存的大小和百分比。通过Dominator Tree视图可以很容易的找出占用内存最多的几个对象(根据Retained Heap或Percentage排序)。Histogram视图和Dominator Tree视图都是可以用来帮助我们定位溢出源的。前者是基于类的角度,后者是基于对象实例的角度。Dominator Tree视图可以更方便的看出其引用关系。

2.4 Top Consumers视图

进入Top Consumers视图

  • Overview页面的Actions部分有进入Top Consumers视图的快捷方式。

    Top Consumers视图使用

       Top Consumers视图以图形化的方式列出最大的object,可以按照object、class、classloader和package进行group by。说白了就是方便我们通过不同的方式站到占内存最大的对象。

  • 按照对象查看内存占用
  • 按照类查看内存占用
  • 按照类加载查看内存占用
  • 按照包名查看内存占用(根据包我们知道哪些公共用的到jar或自己的包占用。这样就可以看到包和包中哪些类的占用比较高)

2.5 Duplicate Classes视图

进入Duplicate Classes视图

  • Overview页面的Actions部分有进入Duplicate Classes视图的快捷方式。

    Duplicate Classes视图使用

       Duplicate Classes视图列出了被加载多次的类,结果按类加载器进行分组,目标是加载同一个类多次被类加载器加载。使用Duplicate Classes视图很容易找到部署应用的时候使用了同一个库的多个版本的问题。

三 MAT报告

3.1 Leak Suspects(内存泄露报告)


Leak Suspects进入

  • 使用MAT打开一个dump文件的时候,会弹出向导菜单,保持默认选项,点Finish,就会导向 Leak Suspects内存泄露报告页面。
  • 工具栏中点击Run Expect System Test > Leak Suspects按钮(区域三常用工具栏的第六个按钮)。
  • Overview页面的Reports部分有进入Leak Suspects的快捷方式

Leak Suspects使用

       Leak Suspects 列出了MAT帮我们分析的可能有内存泄露嫌疑的地方。MAT工具分析了heap dump文件之后非常直观的展示了一个饼图,饼图深色区域被怀疑有内存泄漏的地方。而且下面会给出对怀疑内存泄露地方的具体描述信息。

       针对MAT帮我们分析出来的可能有内存泄露的地方。我们也可以进入查看怀疑地方的详细信息(Leak Suspects如果有怀疑的地方)。

  • Description: 对怀疑内存泄露地方的一个描述信息。
  • Shortest Paths To the Accumulation Point: 展示怀疑内存泄露对象的Path to GC Roots(就是持有可能泄漏内存对象的最近一层)。这个视图的作用是可以分析是由于和哪个GC root相连导致当前Retained Heap占用相当大的对象无法被回收。由于是分析内存泄露的报告,找到导致当前对象无法被回收的GC roots,分析这些GC roots是否合理,是有必要的。
  • Accumulated Objects in Dominator Tree:以对象的维度展示了以怀疑对象为根的Dominator Tree支配树。 可以方便的看出受当前对象“支配”的对象中哪个占用Retained Heap比较大。
  • Accumulated Objects by Class in Dominator Tree:展示了以对象对象为根的Dominator Tree支配树,并以Class类分组。
  • All Accumulated Objects by Class:列举了怀疑对象所存储的所有内容。

3.2 Top Components

Top Components进入

  • 工具栏中点击Run Expect System Test > Top Components按钮(区域三常用工具栏的第六个按钮)。
  • Overview页面的Reports部分有进入Top Components的快捷方式

Top Components使用

       可以针对那些占用堆内存超过整个堆内存1%大小的组件做一系列的分析。

       如上图所示,列出报告中总内存占用大于1%的组件。点击每个组件。有可以查看每个组件的详细信息。如下图所示(点击组件之后进入):

  • 饼图:展示内存占用大小。
  • Top Consumers:以图形化的方式列出最大的object,上文中有讲到Top Consumers哦
  • Retaines Set:是这个对象本身和他持有引用的对象和这些对象的retained set所占内存大小的总和。
  • Possible Memory Waste:可能的内存垃圾。有一下几个部分。
  • Duplicate Strings: 重复的字符串。
  • Empty Collections: 空集合。
  • Collection Fill Ratios: 集合使用率。
  • Miscellaneous:
  • Soft Reference Statistics: 软引用统计。
  • Weak Reference Statistics: 弱引用统计。
  • Finalizer Statistics: Finalizer统计(设计Java Finalizer的使用)。
  • Map Collision Ratios: Map碰撞比例。

Leak Suspects用于查找内存泄漏问题,Top Components负责分析占用堆内存超过整个堆内存1%大小的组件。

四 线程视图

       线程视图首先给出了在生成快照那个时刻,JVM中的Java线程对象列表。

进入线程视图

  • 工具栏中点击线程视图按钮。

线程视图的使用

       在线程视图这个表中,可以看到以下几个信息:线程对象的名字、线程名、线程对象占用的堆内存大小、线程对象的保留堆内存大小、线程的上下文加载器、是否为守护线程。

       选中某个线程对象展开,可以看到线程的调用栈和每个栈的局部变量,通过查看线程的调用栈和局部变量的内存大小,可以找到在哪个调用栈里分配了大量的内存。

       上面我们仅仅是对MAT工具做了一个简单的介绍,后续我们会根据一些实例,结合MAT的使用。做进一步的介绍。

以上是关于java堆简单介绍的主要内容,如果未能解决你的问题,请参考以下文章

堆排序及java版实现

深入了解JVW

Java堆分析器 - Eclipse Memory Analyzer Tool(MAT)

Java堆分析器 - Eclipse Memory Analyzer Tool(MAT)

JVM内存溢出及配置

选择排序——堆排序