JVM学习十三:JVM之堆分析

Posted pony1223

tags:

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

本章进入JVM学习的最后一节,此节主要分析的是堆,因为堆是JAVA程序中最常用使用到的地方,因此对这个地方有必要进行下细致的分析特别是OOM,言归正传,进入正文。

一、内存溢出(OOM)的原因

在JVM中,有哪些内存区间?
技术分享图片
堆溢出
public static void main(String args[]){
    ArrayList<byte[]> list=new ArrayList<byte[]>();
    for(int i=0;i<1024;i++){
        list.add(new byte[1024*1024]);
    }
}

技术分享图片

技术分享图片

技术分享图片

 

永久区
生成大量的类
public static void main(String[] args) {
    for(int i=0;i<100000;i++){
        CglibBean bean = new CglibBean("geym.jvm.ch3.perm.bean"+i,new HashMap());
    }
}

技术分享图片

技术分享图片

 

Java栈溢出
 
这里的栈溢出指,在创建线程的时候,需要为线程分配栈空间,这个栈空间是向操作系统请求的,如果操作系统无法给出足够的空间,就会抛出OOM
技术分享图片
public static class SleepThread implements Runnable{
    public void run(){
        try {
            Thread.sleep(10000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public static void main(String args[]){
    for(int i=0;i<1000;i++){
        new Thread(new SleepThread(),"Thread"+i).start();
        System.out.println("Thread"+i+" created");
    }
}

技术分享图片

技术分享图片

技术分享图片

 

直接内存溢出
ByteBuffer.allocateDirect()无法从操作系统获得足够的空间
技术分享图片
for(int i=0;i<1024;i++){
    ByteBuffer.allocateDirect(1024*1024);
    System.out.println(i);
      System.gc();
}

技术分享图片

技术分享图片

技术分享图片

技术分享图片

 

二、MAT使用基础

浅堆(Shallow Heap)与深堆(Retained Heap)
显示入引用(incoming)和出引用(outgoing)
支配树

nMemory Analyzer(MAT)
n基于Eclipse的软件
nhttp://www.eclipse.org/mat/
 技术分享图片

技术分享图片技术分享图片

技术分享图片技术分享图片

 

 技术分享图片

 

 技术分享图片                                       技术分享图片

技术分享图片

技术分享图片

 技术分享图片

技术分享图片

 

 技术分享图片

 

 技术分享图片

技术分享图片技术分享图片技术分享图片

技术分享图片

技术分享图片

浅堆
一个对象结构所占用的内存大小
 技术分享图片
–3个int类型以及一个引用类型合计占用内存3*4+4=16个字节。再加上对象头的8个字节,因此String对象占用的空间,即浅堆的大小是16+8=24字节
–对象大小按照8字节对齐
–浅堆大小和对象的内容无关,只和对象的结构有关
 深堆
–一个对象被GC回收后,可以真实释放的内存大小
–只能通过对象访问到的(直接或者间接)所有对象的浅堆之和 (支配树)

 技术分享图片技术分享图片

技术分享图片

 

 技术分享图片

技术分享图片

可以看到,所有的Point实例浅堆和深堆的大小都是16字节。而dLine对象,浅堆为16字节,深堆也是16字节,这是因为dLine对象内的两个点f和g没有被设置为null,因此,即使dLine被回收,f和g也不会被释放。对象cLine内的引用对象d和e由于仅在cLine内还存在引用,因此只要cLine被释放,d和e必然也作为垃圾被回收,即d和e在cLine的保留集内,因此cLine的深堆为16*2+16=48字节。
对于aLine和bLine对象,由于两者均持有对方的一个点,因此,当aLine被回收时,公共点a在bLine中依然有引用存在,故不会被回收,点a不在aLine对象的保留集中,因此aLine的深堆大小为16+16=32字节。对象bLine与aLine完全一致。

三、使用Visual VM分析堆

– java自带的多功能分析工具,可以用来分析堆Dump

类的柱状图 ,显示对象数量,总大小等:

 技术分享图片

从类试图切换到实例试图,显示所有的实例:

技术分享图片

 技术分享图片

 技术分享图片

使用OQL查询:

 技术分享图片

返回引用了(0,0)这个点的所有对象

 技术分享图片

 

四、Tomcat OOM分析案例

Tomcat 在接收大量请求时发生OOM,获取堆Dump文件,进行分析。

如果是session过多引起OOM

–  OOM由于保存session过多引起,可以考虑增加堆大小

–  如果应用允许,缩短session的过期时间,使得session可以及时过期,并回收

PS:具体的分析逻辑太长,此处不做详细介绍,可以参考附件。

 

感谢大家的学习,thank you !  后面将进入多线程学习系列,敬请关注。 

 

参考文献:

葛一鸣《深入JVM内核》视频学习

以上是关于JVM学习十三:JVM之堆分析的主要内容,如果未能解决你的问题,请参考以下文章

JVM学习笔记六:运行时数据区之堆

JVM之堆

JVM之堆空间

JVM之堆内存

JVM之堆内存(年经代,老年代)

Spark学习之路 (十三)SparkCore的调优之资源调优JVM的基本架构