美文网首页
深入JVM内核原理-9.Java堆分析

深入JVM内核原理-9.Java堆分析

作者: 笨鸡 | 来源:发表于2019-08-05 00:50 被阅读0次

    1.概要

    • 内存溢出(OOM)的原因
    • MAT使用基础
      • 浅堆(Shallow Heap)与深堆(Retained Heap)
      • 显示入引用(incoming)和出引用(outgoing)
      • 支配树
    • 使用Visual VM分析堆
    • Tomcat OOM分析案例

    2.内存溢出(OOM)的原因

    • 在JVM中,有哪些内存区间
      • 永久区
      • 线程栈
      • 直接内存
    • 堆溢出
      public static void main(String[] args) {
          ArrayList<byte[]> list = new ArrayList<>();
          for (int i = 0; i < 1024*10; i++) {
              list.add(new byte[1024*1024]);
          }
      }
      
      Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at GC.Test3.main(Test3.java:12)
      
      • 解决方法:增大堆空间,及时释放内存
    • 永久区
      • -XX:MetaspaceSize=1m -XX:MaxMetaspaceSize=1m -XX:+PrintGCDetails
      public class Test3 {
         public static void main(String[] args) {
            for (int i = 0; i < 1000000; i++) {
                CglibBean bean = new CglibBean("geym.jvm.ch3.perm.bean"+i,new HashMap());
            }
        }
      }
      
      class CglibBean {
        /**
         * 实体Object
         */
        public Object object = null;
      
      
        /**
         * 属性map
         */
        public BeanMap beanMap = null;
      
      
        public CglibBean() {
            super();
        }
      
      
        @SuppressWarnings("unchecked")
        public CglibBean(String name, Map propertyMap) {
            this.object = generateBean(name, propertyMap);
            this.beanMap = BeanMap.create(this.object);
        }
      
      
        /**
         * 给bean属性赋值
         *
         * @param property 属性名
         * @param value    值
         */
        public void setValue(String property, Object value) {
            beanMap.put(property, value);
        }
      
      
        /**
         * 通过属性名得到属性值
         *
         * @param property 属性名
         * @return 值
         */
        public Object getValue(String property) {
            return beanMap.get(property);
        }
      
      
        /**
         * 得到该实体bean对象
         *
         * @return
         */
        public Object getObject() {
            return this.object;
        }
      
      
        @SuppressWarnings("unchecked")
        private Object generateBean(String name, Map propertyMap) {
            BeanGenerator generator = new BeanGenerator();
            Set keySet = propertyMap.keySet();
            for (Iterator i = keySet.iterator(); i.hasNext(); ) {
                String key = name + (String) i.next();
                generator.addProperty(key, (Class) propertyMap.get(key));
            }
            return generator.create();
        }
      }
      
      Error occurred during initialization of VM
      OutOfMemoryError: Metaspace
      
      • 解决方法:增大永久区,允许Class回收
    • Java栈溢出
      • 这里的栈溢出指,在创建线程的时候,需要为线程分配栈空间,这个栈空间是向操作系统请求的,如果操作系统无法给出足够的空间,就会抛出OOM

      设置堆空间 -Xmx1m -Xss1m

        public static void main(String[] args) {
            for (int i = 0; i < 10000; i++) {
                new Thread(new SleepThread(), "Thread" + i).start();
                System.out.println("Thread" + i + " created");
            }
        }
      
        public static class SleepThread implements Runnable{
      
            @Override
            public void run() {
                try {
                    Thread.sleep(100000000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
      
      Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at GC.Test3.main(Test3.java:11)
      
      • 解决方法:减少堆内存,减少线程栈大小
    • 直接内存溢出
      • ByteBuffer.allocateDirect()无法从操作系统获得足够的空间

      -Xmx1m -XX:+PrintGCDetails

      for (int i = 0; i < 1024; i++) {
           ByteBuffer.allocateDirect(1024*1024*10);
           System.out.println(i);
           System.gc();
      }
      
        [GC (Allocation Failure) [PSYoungGen: 1024K->488K(1536K)] 1024K->624K(5632K), 0.0035865 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
        [GC (System.gc()) [PSYoungGen: 1393K->504K(1536K)] 1529K->724K(5632K), 0.0007902 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
        [Full GC (System.gc()) [PSYoungGen: 504K->0K(1536K)] [ParOldGen: 220K->654K(4096K)] 724K->654K(5632K), [Metaspace: 3408K->3408K(1056768K)], 0.0077157 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
        Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
            at java.nio.Bits.reserveMemory(Bits.java:694)
            at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
            at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)
            at GC.Test3.main(Test3.java:12)
        Heap
         PSYoungGen      total 1536K, used 133K [0x00000000ffe00000, 0x0000000100000000, 0x0000000100000000)
          eden space 1024K, 13% used [0x00000000ffe00000,0x00000000ffe214d8,0x00000000fff00000)
          from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
          to   space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
         ParOldGen       total 4096K, used 654K [0x00000000ffa00000, 0x00000000ffe00000, 0x00000000ffe00000)
          object space 4096K, 15% used [0x00000000ffa00000,0x00000000ffaa39a0,0x00000000ffe00000)
         Metaspace       used 3497K, capacity 4496K, committed 4864K, reserved 1056768K
          class space    used 384K, capacity 388K, committed 512K, reserved 1048576K
      
      • 解决方法:减少堆内存,有意触发GC

    3.MAT使用基础

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

    4.使用Visual VM分析堆

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

    5.Tomcat OOM分析案例

    • Tomcat OOM
      • Tomcat在接受大量请求时发生OOM,获取堆Dump文件,进行分析。
    • 使用MAT打开堆
    • 分析目的:
      • 找出OOM的原因
      • 推测系统OOM时的状态
      • 给出解决这个OOM的方法
    • 解决方法:
      • OOM由于保存session过多引起,可以考虑增加堆大小
      • 如果应用允许,缩短session的过期时间,使得session可以及时过期,并回收

    相关文章

      网友评论

          本文标题:深入JVM内核原理-9.Java堆分析

          本文链接:https://www.haomeiwen.com/subject/mriudctx.html