StackOverflowError 和 OutOfMemoryError 有什么区别以及如何在应用程序中避免它们?
11 回答
简短的回答:
OutOfMemoryError
与堆有关。StackOverflowError
与堆栈有关
长答案:
开始时,JVM
您可以定义它可以用于处理的 RAM 量。JVM
出于处理目的将其划分为某些内存位置,其中两个是Stack
&Heap
如果您在内存中有大对象(或)引用的对象,那么您将看到OutofMemoryError
. 如果您对对象有强引用,则 GC 无法清理为该对象分配的内存空间。当 JVM 尝试为新对象分配内存并且没有足够的可用空间时,它会抛出OutofMemoryError
,因为它无法分配所需的内存量。
如何避免:确保不需要的对象可用于 GC
您所有的局部变量和方法调用相关数据都将在堆栈上。对于每个方法调用,将创建一个堆栈框架,并将本地以及与方法调用相关的数据放置在堆栈框架内。一旦方法执行完成,堆栈帧将被删除。重现此问题的一种方法是,对方法调用进行无限循环,您将看到stackoverflow
错误,因为每次调用的堆栈帧都将填充方法数据,但不会被释放(删除)。
如何避免:确保方法调用结束(不是无限循环)
Imagine you have a function like the following
public void f(int x) {
return f(x + 1);
}
When you'll call it the call will call f
again and again and again. At each call a bit of information is stored on the stack. Since the stack is limited in size you will get a StackOverflowError
.
Now imagine the following code:
for (int i = 1; i > 0; i++)
vector.add(new BigObject());
where BigObject
is a normal Java object. As you see, the loop never terminates. Each allocation is done on the heap thus it will be filled with BigObject
s and you will get an OutOfMemoryError
.
To recap:
OutOfMemoryError
is thrown when you are creating objectsStackOverflowError
is thrown when you are calling functions
StackOverflowError
当您在另一个内部执行太多方法(例如使用无限递归)时会发生这种情况,这受堆栈大小的限制。
OutOfMemoryError
happens when the JVM runs out of space to allocate new objects, which are allocated on the heap.
In Java Virtual Machine there are several memory area defined :
- Java Virtual Machine stacks
- Heap area
- Method area
- Run time constant pool
- Native method stacks
In all above, you can choose your precision that memory allocated to those memory area will be fixed or will be changed dynamically at runtime.
Now about the question, OutOfMemoryError
is applicable for all of the above listed. OutOfMemoryError
will be thrown if memory expansion of any of the memory area will be attempted but enough memory is not available to allocate.
and StackOverFlowError
is applicable for Native Method Stack and Java Virtual Machine Stack. StackOverFlowError
will be thrown If the computation in a thread requires a larger stack than is permitted.
For Detailed reference you can read THE STRUCTURE OF THE JAVA VIRTUAL MACHINE
There are two(2) areas in memory the heap and stack.
- stack memory is used to store local variables and function call.
- heap memory is used to store objects in Java
If there is no memory left in stack for storing function call or local variable, JVM will throw java.lang.StackOverFlowError,
while if there is no more heap space for creating object, JVM will throw java.lang.OutOfMemoryError:
The following exceptional conditions are associated with Java Virtual Machine stacks:
If the computation in a thread requires a larger Java Virtual Machine stack than is permitted, the Java Virtual Machine throws a StackOverflowError.
If Java Virtual Machine stacks can be dynamically expanded, and expansion is attempted but insufficient memory can be made available to effect the expansion, or if insufficient memory can be made available to create the initial Java Virtual Machine stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.
The following exceptional condition is associated with the heap:
If a computation requires more heap than can be made available by the automatic storage management system, the Java Virtual Machine throws an OutOfMemoryError.
The following exceptional condition is associated with the method area:
If memory in the method area cannot be made available to satisfy an allocation request, the Java Virtual Machine throws an OutOfMemoryError.
The following exceptional condition is associated with the construction of the run-time constant pool for a class or interface:
When creating a class or interface, if the construction of the run-time constant pool requires more memory than can be made available in the method area of the Java Virtual Machine, the Java Virtual Machine throws an OutOfMemoryError.
The following exceptional conditions are associated with native method stacks:
If the computation in a thread requires a larger native method stack than is permitted, the Java Virtual Machine throws a StackOverflowError.
If native method stacks can be dynamically expanded and native method stack expansion is attempted but insufficient memory can be made available, or if insufficient memory can be made available to create the initial native method stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.
https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-2.html
2.5.2. Java Virtual Machine Stacks
2.5.3. Heap
2.5.4. Method Area
2.5.5. Run-Time Constant Pool
2.5.6. Native Method Stacks
2.6. Frames
StackOverflowError
- It is related to Stack memory.
- It occurs when Stack is full.
- It is thrown when you call a method and there is no space left in the stack.
- It occurs when you are calling a method recursively without proper terminating condition.
- How to avoid? Make sure that methods are finishing their execution and leaving the stack memory.
OutOfMemoryError
- It is related to heap memory.
- It occurs when heap is full.
- It is thrown when you create a new object and there is no space left in the heap.
- It occurs when you are creating lots of objects in the heap memory.
- How to avoid? Try to remove references to objects which you don’t need anymore.
StackOverflowError : Thrown when a stack overflow occurs because an application recurses too deeply.
OutOfMemoryError : Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.
From Javadocs: Exceptional conditions associated with JVM Stacks:
1) if insufficient memory can be made available to create the initial JVM stack for a new thread, the JVM throws an OutOfMemoryError.
2) If the computation in a thread requires a larger JVM stack than is permitted, the JVM throws a StackOverflowError.
3) If JVM stack can be dynamically expanded, and expansion is attempted but insufficient memory can be made available to effect the expansion, the JVM throws an OutOfMemoryError.
Exceptional conditions associated with Heap:
1) If a computation requires more heap than can be made available by the automatic storage management system, the JVM throws an OutOfMemoryError.
java.lang.StackOverFlowError:
1) Thrown when stack memory is full
2) The data related to method like parameters, local variables or references to objects are stored in this block. When the method finishes its execution, this block is removed from the stack along with data stored in it.
Whenever you call a method, it must finish its execution and leave the stack memory. If your methods are staying in the stack then stack will be full and JVM will throw java.lang.StackOverflowError.
E.g:
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) Thrown when heap memory is full.
2) JVM is unable to allocate the memory to new objects.
The objects you create in java are stored in the heap memory. When the objects are no more required, they must be removed from the memory. Garbage collector removes the unwanted objects from the heap memory. If your objects have live references, garbage collector doesn’t remove them. It removes only those objects which don’t have live references.
Through the JVM specification, there are 5 data areas.
For JVM Stacks data areas, the spec said the memory size of JVM Stacks can be fixed or dynamically adjustable like the heap area.
When runs out of JVM Stacks memory, there are two cases:
1. If JVM Stacks is implemented as a fixed size, JVM will throw a StackOverflowError.
2. Otherwise, just like the heap area, JVM will throw OutOfMemoryError when failed to allocate more memory.
Any not only for the JVM Stacks area, memory allocations for other data areas will also case OutOfMemoryError due to insufficient memory resources.
For more information, see the JVM specification - Run-Time Data Areas