Java 堆栈及 SOF 与 OOM

问:请分别写出一段堆和栈溢出的 Java 代码片段?
答:代码如下。
public class Test {
   //堆溢出例子OOM
   public void heapException() {  
       for(;;) {  
           ArrayList list = new ArrayList (2000);  
       }
   }

   //栈溢出例子SOF
   int count = 1;  
   public void stackException() {  
       count++;  
       this.stackException();  
   }  

   public static void main(String[] args) {  
       Test test = new Test();  
       test.heapException();  
       test.stackException();     
   }
}

如上可见,递归调用可以导致栈溢出,不断的创建对象可以导致堆溢出。

因为我们定义一个基本数据类型变量、一个对象的引用、函数调用现场等都是保存在 JVM 中的栈空间。而通过 new 关键字和构造器创建的对象一般都放在堆空间,堆是垃圾收集器管理的主要区域。

问:简单说说 StackOverflowError 与 OutOfMemeryError 的区别?

答:区别如下。

  • StackOverflowError:当启动一个新的线程时虚拟机会为其分配一个栈空间,java 栈以帧为单位保存线程运行状态,当线程调用一个方法时,JVM 会压入一个新的栈帧到这个线程的栈空间中,只要这个方法还没返回则这个栈帧就会一直存在。所以如果方法的嵌套调用层次太多(如递归调用),随着栈帧的增加导致总和大于 JVM 设置的 -Xss 值就会抛出 StackOverflowError 异常。

虚拟机栈:线程私有的,每个方法在执行时会创建一个栈帧,用来存储局部变量表、操作数栈、动态连接、方法返回地址等;其中局部变量表用于存放 8 种基本数据类型(boolean、byte、char、short、int、float、long、double)和 reference 类型。每个方法从调用到执行完毕对应一个栈帧在虚拟机栈中的入栈和出栈。

  • OutOfMemoryError:OOM 异常会分几种情况出现。

    • 堆内存溢出:当需要为对象实例化分配堆内存空间时,而堆的占用已经达到了设置的最大值(通过 -Xmx)就会抛出 OutOfMemoryError 异常。

堆:线程共享的,在虚拟机启动时创建,用于存放对象实例。

  • 方法区内存溢出:方法区存放 java 类信息(如类名、访问修饰符、常量池、字段描述、方法描述等),在类加载器加载 class 文件到内存时 JVM 会提取类的这些信息放到方法区,而此时如果需要存储这些类信息且方法区的内存占用又已经达到最大值(通过 -XX:MaxPermSize)则会抛出 OutOfMemoryError 异常。

方法区:线程共享的,用于存储已被虚拟机加载的类信息、常量、静态变量等。

本文参考自 Java 堆栈及 SOF 与 OOM 相关笔试题解析

你可能感兴趣的:(Java 堆栈及 SOF 与 OOM)