1. 定义
OutOfMemoryError (OOM):
表示 内存不足,通常在 JVM 尝试分配对象时发现没有足够的堆、元空间或其他内存区域来完成分配。
原因包括:创建过多对象、内存泄漏、配置的内存过小。
StackOverflowError (SOE):
表示 栈内存溢出,通常发生在递归调用太深或方法调用层次过多时,导致栈空间耗尽。
该错误通常是由于程序设计问题,如无限递归。
2. 发生的区域
OutOfMemory:
Java 堆(Heap)空间不足(最常见)。
元空间(Metaspace)不足。
本地内存(Native Memory)不足。
直接内存(Direct Memory)不足。
GC 过载导致
GC Overhead Limit Exceeded
。
StackOverflow:
发生在栈内存区域,主要是方法调用栈深度超过栈大小限制。
3. 异常处理
OutOfMemory:
是一种 严重错误,需要通过调优代码或调整 JVM 配置来解决。
常见解决方法:
增加堆内存(如
-Xmx
)。分析并修复内存泄漏。
优化对象生命周期。
StackOverflow:
是 程序设计问题,通常通过检查递归逻辑或优化代码调用链来解决。
常见解决方法:
优化递归代码,改为迭代实现。
增加栈大小(如
-Xss
)。
4. 代码示例
1. Java 堆溢出(OutOfMemoryError: Java Heap Space)
import java.util.ArrayList;
import java.util.List;
public class HeapOOM {
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
while (true) {
list.add(new Object()); // 不断创建对象导致堆溢出
}
}
}
解决方法:通过 -Xmx
参数增加堆内存大小。
2. 栈溢出(StackOverflowError)
public class StackOverflow {
public static void main(String[] args) {
recursiveCall(); // 无限递归调用
}
public static void recursiveCall() {
recursiveCall(); // 方法调用自身,导致栈溢出
}
}
解决方法:优化递归逻辑,或者增加栈大小(-Xss
)。
3. 元空间溢出(OutOfMemoryError: Metaspace)
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
public class MetaspaceOOM {
public static void main(String[] args) {
while (true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Object.class);
enhancer.setUseCache(false);
enhancer.setCallback((MethodInterceptor) (obj, method, args1, proxy) -> proxy.invokeSuper(obj, args1));
enhancer.create(); // 不断动态生成类导致元空间溢出
}
}
}
解决方法:通过 -XX:MaxMetaspaceSize
参数增加元空间大小。
5. 关键区别
总结
OutOfMemoryError:内存不足的表现,通常与资源配置和程序内存使用有关。
StackOverflowError:栈溢出问题,通常是程序设计问题,如无限递归或深层调用链。
JVM 中合理配置内存参数(堆和栈大小)以及优化代码设计可以避免大多数这类问题。