Java虚拟机栈OOM(StackOverflowError/OutOfMemoryError)
Java虚拟机栈OOM是指线程请求的栈深度超过虚拟机允许的最大深度(StackOverflowError)或虚拟机栈扩展时无法申请到足够内存(OutOfMemoryError)。
两种主要错误类型
-
StackOverflowError
- 当线程请求的栈深度超过虚拟机允许的最大深度时抛出
- 通常由无限递归或方法调用层次过深引起
-
OutOfMemoryError
- 当Java虚拟机栈可以动态扩展,但扩展时无法申请到足够内存时抛出
- 通常由创建过多线程导致
常见原因
导致StackOverflowError的原因
- 无限递归调用(最常见)
- 方法调用层次过深(如复杂的递归算法)
- 大量局部变量占用栈空间
导致OutOfMemoryError的原因
- 创建过多线程,每个线程都需要独立的栈空间
- 设置的栈空间过大(-Xss参数),导致总内存不足
示例代码
StackOverflowError示例
java
public class StackOverflowExample {
public static void recursiveCall() {
recursiveCall(); // 无限递归
}
public static void main(String[] args) {
recursiveCall();
}
}
OutOfMemoryError示例
java
public class ThreadOOMExample {
public static void main(String[] args) {
while (true) {
new Thread(() -> {
try {
Thread.sleep(10000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}
解决方案
-
对于StackOverflowError
- 检查并修复无限递归
- 将递归算法改为迭代实现
- 增加栈大小(-Xss参数),但这只是临时解决方案
-
对于OutOfMemoryError
- 减少线程数量
- 减小每个线程的栈大小(-Xss)
- 优化程序逻辑,避免创建过多线程
- 增加JVM总内存
JVM参数调整
-Xss<size>
: 设置每个线程的栈大小,如 -Xss1m-XX:ThreadStackSize=<size>
: 另一种设置栈大小的方法
诊断工具
jstack
: 查看线程堆栈信息- JVisualVM: 可视化监控线程和内存使用情况
- Memory Analyzer Tool (MAT): 分析内存使用情况
最佳实践
- 谨慎使用递归,确保有终止条件
- 控制线程数量,使用线程池管理线程
- 合理设置栈大小,不要过大或过小
- 定期进行代码审查,查找潜在的内存问题