StackOverflowError和OutOfMemoryError之间的区别是什么以及如何在应用程序中避免它们?
答案 0 :(得分:67)
简答:
OutOfMemoryError
与Heap有关。 StackOverflowError
与堆栈答案很长:
当您启动JVM
时,您可以定义可用于处理的RAM量。 JVM
将其划分为某些内存位置以用于其处理目的,其中两个是 Stack
& Heap
强>
如果内存中有大对象(或)引用的对象,那么您将看到OutofMemoryError
。如果您对对象有强引用,则GC无法清除为该对象分配的内存空间。当JVM尝试为新对象分配内存而没有足够的可用空间时,它会抛出OutofMemoryError
,因为它无法分配所需的内存量。
如何避免:确保GC无法使用不必要的对象
所有局部变量和方法调用相关数据都将在堆栈中。对于每个方法调用,将创建一个堆栈帧,并将本地以及与方法调用相关的数据放置在堆栈帧内。方法执行完成后,将删除堆栈帧。重现这一点的一种方法是,有一个无限循环的方法调用,你会看到stackoverflow
错误,因为堆栈帧将填充每个调用的方法数据但不会被释放(删除)。
如何避免:确保方法调用结束(不是在无限循环中)
答案 1 :(得分:5)
想象一下,你有类似以下的功能
public void f(int x) {
return f(x + 1);
}
当您拨打电话时,通话会一次又一次地呼叫f
。在每次调用时,一些信息存储在堆栈中。由于堆栈的大小有限,您将获得StackOverflowError
。
现在想象下面的代码:
for (int i = 1; i > 0; i++)
vector.add(new BigObject());
其中BigObject
是普通的Java对象。如您所见,循环永远不会终止。每个分配都在堆上完成,因此它将被BigObject
填充,您将获得OutOfMemoryError
。
回顾一下:
OutOfMemoryError
StackOverflowError
答案 2 :(得分:3)
StackOverflowError
,这受到堆栈的大小的限制。
OutOfMemoryError
。
答案 3 :(得分:2)
在Java虚拟机中,定义了几个内存区域:
在上面的所有内容中,您可以选择精确分配给这些内存区域的内存将被修复或将在运行时动态更改。
现在关于这个问题,OutOfMemoryError
适用于上面列出的所有内容。如果将尝试任何内存区域的内存扩展但是没有足够的内存可用于分配,则将抛出OutOfMemoryError
。
和StackOverFlowError
适用于本机方法堆栈和 Java虚拟机堆栈。如果线程中的计算需要的堆栈大于允许的堆栈,则抛出StackOverFlowError
。
答案 4 :(得分:1)
堆和堆栈在内存中有两(2)个区域。
如果堆栈中没有用于存储函数调用或局部变量的内存,JVM将抛出 java.lang.StackOverFlowError ,
如果没有更多的堆空间来创建对象,JVM将抛出 java.lang.OutOfMemoryError :
答案 5 :(得分:1)
以下异常情况与Java虚拟机堆栈相关联:
如果线程中的计算需要更大的Java虚拟机 堆栈比允许的堆栈,Java虚拟机抛出一个 的 的StackOverflowError 强>
如果可以动态扩展Java虚拟机堆栈,并且 尝试扩展但可以提供不足的内存 实现扩展,或者如果内存不足 可用于为新的创建初始Java虚拟机堆栈 线程,Java虚拟机抛出 OutOfMemoryError 。
以下异常情况与堆相关联:
如果计算需要的堆数多于可用的堆 自动存储管理系统,Java虚拟机抛出 OutOfMemoryError 。
以下异常情况与方法区域相关联:
如果方法区域中的内存无法满足 分配请求,Java虚拟机抛出一个 的 的OutOfMemoryError 强>
以下异常情况与类或接口的运行时常量池的构造相关联:
创建类或接口时,如果构造了 运行时常量池需要的内存比可用内存多 在Java虚拟机的方法区域中,Java Virtual 机器抛出 OutOfMemoryError 。
以下异常条件与本机方法堆栈相关联:
如果线程中的计算需要比允许的更大的本机方法堆栈,则Java虚拟机会抛出一个 的StackOverflowError。强>
如果本机方法堆栈可以动态扩展和本机方法 尝试堆栈扩展但可以进行不充分的内存 可用,或者如果可以创建的内存不足 新线程的初始本机方法堆栈,Java Virtual 机器抛出 OutOfMemoryError 。
https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-2.html
2.5.2。 Java虚拟机堆栈
2.5.3。堆
2.5.4。方法区
2.5.5。运行时常量池
2.5.6。本机方法堆栈
2.6。帧
答案 6 :(得分:1)
StackOverflowError
OutOfMemoryError
答案 7 :(得分:0)
StackOverflowError:由于应用程序过于冗长而发生堆栈溢出时抛出。
OutOfMemoryError:当Java虚拟机由于内存不足而无法分配对象时抛出,垃圾收集器不再提供更多内存。
答案 8 :(得分:0)
来自Javadocs: 与JVM堆栈相关的异常条件:
1)如果没有足够的内存可用于为新线程创建初始JVM堆栈,则JVM会抛出OutOfMemoryError。
2)如果线程中的计算需要比允许的更大的JVM堆栈,则JVM会抛出StackOverflowError。
3)如果可以动态扩展JVM堆栈,并且尝试扩展但是没有足够的内存可用于实现扩展,则JVM会抛出OutOfMemoryError。
与Heap相关的特殊情况:
1)如果计算需要的堆量超过自动存储管理系统可用的堆,则JVM会抛出OutOfMemoryError。
答案 9 :(得分:0)
java.lang.StackOverFlowError:
1)当堆栈内存已满时抛出
2)与方法有关的数据,例如参数,局部变量或对对象的引用,都存储在此块中。该方法执行完毕后,将从堆栈中删除此块以及其中存储的数据。
每当您调用方法时,它都必须完成其执行并离开堆栈内存。如果您的方法保留在堆栈中,则堆栈将已满,并且JVM将抛出java.lang.StackOverflowError。
例如:
public class FactorialExample
{
private static void factorial(int i)
{
factorial((i+1) * i); //calling itself with no terminating condition
}
public static void main(String[] args)
{
factorial(1);
}
}
java.lang.OutOfMemoryError:
1)堆内存已满时抛出。
2)JVM无法将内存分配给新对象。
您在Java中创建的对象存储在堆内存中。当不再需要这些对象时,必须将其从内存中删除。垃圾收集器从堆内存中删除不需要的对象。如果您的对象具有实时引用,则垃圾收集器不会删除它们。它只会删除那些没有实时引用的对象。
答案 10 :(得分:0)
根据JVM规范,有5个数据区域。
对于JVM Stacks数据区域,规范说JVM Stacks的内存大小可以是固定的,也可以像堆区域一样动态可调。
当JVM Stacks内存用完时,有两种情况:
1.如果将JVM堆栈实现为固定大小,则JVM将抛出 StackOverflowError 。
2.否则,就像堆区域一样,当分配更多内存失败时,JVM将抛出 OutOfMemoryError 。
不仅对于JVM堆栈区域,由于内存资源不足,其他数据区域的内存分配也会发生OutOfMemoryError。
有关更多信息,请参见JVM specification - Run-Time Data Areas