Java中的StackOverflowError与OutOfMemoryError

时间:2020-01-09 10:34:58  来源:igfitidea点击:

在处理和运行Java应用程序时,我们可能会遇到与内存相关的这两个错误中的任何一个,即StackOverflowError和OutOfMemoryError。在本文中,我们将看到Java中StackOverflowError和OutOfMemoryError之间的区别。

Java中的StackOverflowError

为每个JVM线程创建一个JVM堆栈。每当调用方法时,都会创建一个新框架并将其推送到该线程的JVM堆栈中。每个帧都存储与方法相关的数据,例如局部变量,操作数堆栈和对当前方法类的运行时常量池的引用。一旦方法执行完成,堆栈框(针对该方法)就会弹出堆栈。

如果执行任何方法都需要比允许的堆栈大的堆栈,则Java虚拟机将引发StackOverflowError。当我们具有无终止条件的递归方法时,可能会看到StackOverflowError。

例如,一个Java程序以递归方式打印偶数而没有任何终止条件。

public class StatckOverFlowErrorExample {
  public static void main(String[] args) {
    printEven(1);
  }
	
  private static int printEven(int i) {
    if(i % 2 != 0) {
      i++;
    }
    System.out.println(i);
    return i + printEven(i + 2);
  }
}

输出:

20808
20810
20812
Exception in thread "main" java.lang.StackOverflowError
	at java.base/java.io.PrintStream.write(PrintStream.java:605)
	at java.base/java.io.PrintStream.print(PrintStream.java:676)
	at java.base/java.io.PrintStream.println(PrintStream.java:812)
	at com.theitroad.proj.Programs.StatckOverFlowErrorExample.printEven(StatckOverFlowErrorExample.java:14)
	at com.theitroad.proj.Programs.StatckOverFlowErrorExample.printEven(StatckOverFlowErrorExample.java:15)

Java中的OutOfMemoryError

每当我们为该对象创建新对象时,该对象的内存就会分配到堆上。实例变量和数组也存储在堆中。

一旦存储在堆上的对象没有任何引用,垃圾收集器就会回收该对象的内存。如果存在对对象的引用,则GC无法删除这些对象,如果我们有大量此类引用的对象,并且JVM尝试为新对象分配堆内存,则JVM会抛出java.lang.OutOfMemoryError,因为堆内存不足剩下。

尝试分配大于堆大小的数组也会导致OutOfMemoryError。

public static void main(String[] args) {
	Integer[] array = new Integer[1000*1000*1000];
}

输出:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

Java中的StackOverflowError与OutOfMemoryError

StackOverflowError </ strong>OutOfMemoryError </ strong>
堆栈已满</ em>时,将引发StackOverflowError。堆空间已满</ em>时,将引发OutOfMemoryError。
调用任何方法时,堆栈用于存储与方法相关的数据。因此,如果没有足够的空间来存储方法数据,则会引发StackOverflowError。堆内存用于存储对象,实例变量和数组。因此,当没有空间创建新对象,数组时,将引发OutOfMemoryError。
没有终止条件的递归方法会导致StackOverflowError。许多具有实时引用的对象,因此GC无法取消分配这些对象会导致OutOfMemoryError。
要避免StackOverflowError,请确保方法正在按逻辑执行并终止,以便可以从堆栈中取出已执行方法的堆栈框架。要避免OutOfMemoryError,请确保不再从任何地方引用不再需要的对象被垃圾收集。还请确保不要创建非常大的对象或者数组。