Java虚拟机就是一个抽象的计算模型,就如同一台真实的机器,它有自己的指令集合执行引擎,可以在运行时操控内存区域。目的是为了给运行的应用程序提供一个运行环境。JVM可以解毒指令代码并与底层进交互:把包括操作系统平台和执行指令并管理资源的硬件体系结构
1. 简述
JVM提供的内存管理机制和垃圾回收机制极大地解放了用户对内存的管理,大部分情况不会出现内存·泄漏和内存溢出的情况。但是任仍然会有意外,java内存溢出有如下几种情况:
栈内存溢出
堆内存溢出
永久代溢出
2. 栈内存溢出
栈内存可以分为虚拟机栈和本地方法栈,除了他们分别位于执行java方法和本地方法,其余原理都是类似的。java虚拟机栈是线程私有的,当线程终的方法被调用时,虚拟机会创建用于保存局部变量表,操作数栈,动态连接和方法出口等信息的栈帧。
具体的来说,当线程执行某个方法时,JVM会创建栈帧并亚栈,此时刚亚栈的栈帧就成为了当前栈帧。如果该方法进行递归调用时JVM每次都会将保存了当前方法数据的栈帧亚栈,每次栈帧中的数据都是当前方法数据的一份拷贝。如果递归次数足够多,多到栈中栈帧所使用的内存超出了栈内存的最大容量。
public class StackOverFlow { private static int stackLength=0; public static void main(String[] args) { StackOverFlow demo=new StackOverFlow(); try { demo.putStack(); }catch(Exception e) { System.out.println("Length:"+demo.stackLength); throw e; } } public void putStack() { stackLength++; putStack(); } }
运行程序很快就会抛出异常。从中发现出现问题的地方就是递归调用方法自身的地方
Exception in thread "main" java.lang.StackOverflowError at Other.StackOverFlow.putStack(StackOverFlow.java:21) at Other.StackOverFlow.putStack(StackOverFlow.java:21) at Other.StackOverFlow.putStack(StackOverFlow.java:21) at Other.StackOverFlow.putStack(StackOverFlow.java:21) at Other.StackOverFlow.putStack(StackOverFlow.java:21) at Other.StackOverFlow.putStack(StackOverFlow.java:21) at Other.StackOverFlow.putStack(StackOverFlow.java:21) at Other.StackOverFlow.putStack(StackOverFlow.java:21) at Other.StackOverFlow.putStack(StackOverFlow.java:21) at Other.StackOverFlow.putStack(StackOverFlow.java:21) at Other.StackOverFlow.putStack(StackOverFlow.java:21) at Other.StackOverFlow.putStack(StackOverFlow.java:21) at Other.StackOverFlow.putStack(StackOverFlow.java:21) at Other.StackOverFlow.putStack(StackOverFlow.java:21)
2.堆内存溢出
堆内存的唯一作用就是存放数组和对象实例,即通过new指令创建的对象,包括数组和引用类型。堆内存溢出有分为两种情况:
堆内存溢出:当堆中对象实例所占空间超出了堆的最大容量,JVM就会抛出OutofMemoryError:java jeap space
堆内存泄漏: 当堆中一些对象不再被引用,但是垃圾回收器无法识别时,这些未使用的对象就会在堆中无限期的存在,不断堆积就会造成内存泄漏
如果是因为堆内存空间太小,可以通过改变 -Xmx 来进行调整,或者分析程序中对象的生命周期和粗糙年初结构等信息进行调整;如果发生了内存泄漏,则可以先找出导致泄漏发生的对象是如何被GC ROOT 引用起来的,然后分析引用链找到发生泄漏的地方。
例如我们通过 -Xms20m -Xmx20m -XX:+HeapDumpOnOutofMemroyError来设置堆内存大小为20M,并且设置不支持自动扩展,同时使用-XX:+HeapDumpOnOutofMemroyError实现异常抛出时,Dump出当前的内存堆转储快照进行分析
public class HeapOOM { static class OOMObject{} public static void main(String[] args) { ArrayList<OOMObject> list=new ArrayList<>(); OOMObject demo=new OOMObject(); try { while(true) { list.add(new OOMObject()); } }catch(Exception e) { System.out.println(list.size()); throw e; } } }
运行一段时间后:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.base/java.util.Arrays.copyOf(Arrays.java:3719) at java.base/java.util.Arrays.copyOf(Arrays.java:3688) at java.base/java.util.ArrayList.grow(ArrayList.java:237) at java.base/java.util.ArrayList.grow(ArrayList.java:242) at java.base/java.util.ArrayList.add(ArrayList.java:467) at java.base/java.util.ArrayList.add(ArrayList.java:480) at Other.HeapOOM.main(HeapOOM.java:13)