java堆用于存储对象实例,只要不断创建对象,并且保证GC Roots(一直GC回收算法)到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么对象在对象数量到达最大堆的容量限制后就会产生内存溢出异常。
java堆异常是实际应用常见的内存溢出异常情况。当出现JAVA堆内存溢出情况时,异常堆栈信息“java,lang.OutOfMemoryError” 跟着进一步提示“java heap space”。
使用内存分析工具对堆内存进行分析,次数使用的是Eclipse memory Analyzer 独立安装。
测试代码:
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("对象初始化完成"); } } }
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); } } }
java.lang.StackOverflowError at com.haihang.exception.OomError.stackLeak(OomError.java:12) 栈的最大深度16726
实验证明:在单线程下内存无法分配时,虚拟机都是抛出StackOverflowError异常。
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()); } } }
java.lang.OutOfMemoryError:Permgen space
在HotSpot虚拟机中Permgen space 属于堆中的永久代。
图片相同的代码逻辑返回的结果却是不一样,因为在jdk1.7以后的intern不在复制,只是在常量池中记录对象的引用,因此intern返回的引用于StringBuilder创建的字符串实例是同一个,所以相同;str2返回false的原因是“java”这个字符在执行toString之前已经出现过,不符合“首次出现”的原则,而计算机软件是首次出现的,因此返回true。