• 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内核》视频学习

  • 相关阅读:
    Python保留最后N个元素
    STL算法
    STL迭代器
    STL容器
    C++总结1
    牛客剑指Offer2
    Vue第一天
    UML
    Java继承和组合代码
    Java15后的sealed阻止继承滥用
  • 原文地址:https://www.cnblogs.com/pony1223/p/9206715.html
Copyright © 2020-2023  润新知