JVM自动内存管理机制 二

OutOfMemryError异常实战

一、java堆溢出

java堆用于存储对象实例,只要不断建立对象,而且保证GC Roots(一直GC回收算法)到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么对象在对象数量到达最大堆的容量限制后就会产生内存溢出异常。java


java堆异常是实际应用常见的内存溢出异常状况。当出现JAVA堆内存溢出状况时,异常堆栈信息“java,lang.OutOfMemoryError” 跟着进一步提示“java heap space”。算法

使用内存分析工具对堆内存进行分析,次数使用的是Eclipse memory Analyzer 独立安装。bash

测试代码:多线程

public class OomError {

    static class OOMObject{

    }

    public static void main(String[] args) {

        List<OOMObject> lists = new ArrayList<>();
        int i = 1;
        while (true){
            i++ ;
            if(i<1000000){
                lists.add(new OOMObject());
            }
            System.out.println("对象初始化完成");
        }
    }
}

复制代码

内存泄漏分析: 工具

因为GC Roots引用链的信息,对象没有被回收,经过分析能够准肯定位内存泄漏代码的位置。测试

二、虚拟机栈和本地方法栈溢出

public class OomError {

    private int stackLen = 1;

    public void stackLeak(){

        stackLen ++ ;
        stackLeak();
    }

    public static void main(String[] args) {

        OomError oom = null;
        try{
             oom = new OomError();
            oom.stackLeak();

        }catch (Throwable e){

            e.printStackTrace();
            System.out.println("栈的最大深度"+oom.stackLen);
        }



    }
}

        }catch (Throwable e){

            e.printStackTrace();
            System.out.println("栈的最大深度"+oom.stackLen);
        }



    }
}
复制代码

异常信息:ui

java.lang.StackOverflowError
	at com.haihang.exception.OomError.stackLeak(OomError.java:12)
	栈的最大深度16726
复制代码

实验证实:在单线程下内存没法分配时,虚拟机都是抛出StackOverflowError异常。spa

在多线程下,经过减小最大的堆和减小栈容量来换取更多的线程。线程

方法区和运行时常量池溢出

public class OomError {



    public static void main(String[] args) {
        //保持对象的引用防止GC
      List<String> lists =new ArrayList<>();
      int i=0;
      while(true){
          //intern 为本地方法,做用是先从常量池中查找字符,若是不存在将字符放入常量池
          lists.add(String.valueOf(i++).intern());
      }



    }
}

复制代码

异常信息:code

java.lang.OutOfMemoryError:Permgen space

复制代码

在HotSpot虚拟机中Permgen space 属于堆中的永久代。

图片相同的代码逻辑返回的结果倒是不同,由于在jdk1.7之后的intern不在复制,只是在常量池中记录对象的引用,所以intern返回的引用于StringBuilder建立的字符串实例是同一个,因此相同;str2返回false的缘由是“java”这个字符在执行toString以前已经出现过,不符合“首次出现”的原则,而计算机软件是首次出现的,所以返回true。