Java内存溢出实战:堆溢出与栈溢出的复现及原因解析
Java开发中经常遇到因内存管理不当导致的程序崩溃。本文将直接演示两种典型的内存溢出场景:通过不断创建对象引发的"堆溢出"和通过无限递归引发的"栈溢出",并展示对应的错误日志,帮助初学者理解JVM内存结构的差异。
堆溢出(OOM)
Java堆内存用于存储对象实例。当代码试图在堆中创建新对象,而堆空间不足以容纳时,JVM会抛出java.lang.OutOfMemoryError: Java heap space错误。
示例代码:
import java.util.ArrayList;
import java.util.List;
/**
* 堆溢出示例
*/
public class HeapOutofMemory {
public static void main(String[] args) {
// 使用ArrayList集合持续占用堆内存
List<HeapOutofMemory> list = new ArrayList<>();
while (true) {
// 不断向列表中添加当前类的实例,直到内存耗尽
list.add(new HeapOutofMemory());
}
}
}
运行结果:
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.ArrayList.grow(ArrayList.java:265)
... ...
栈溢出(SOF)
Java虚拟机栈主要用于描述Java方法执行的内存模型。每个方法在执行时会创建一个栈帧,用于存储局部变量表、操作数栈等。如果线程请求的栈深度大于虚拟机所允许的深度,就会抛出java.lang.StackOverflowError。
最常见的情况是方法进行了无限递归调用。
示例代码:
/**
* 栈溢出示例
*/
public class StackOverflow {
public static void main(String[] args) {
new StackOverflow().test();
}
public void test() {
// 方法内部无终止条件的递归调用
test();
}
}
运行结果:
Exception in thread "main" java.lang.StackOverflowError
at StackOverflow.test(JavaDemo.java:14)
at StackOverflow.test(JavaDemo.java:14)
at StackOverflow.test(JavaDemo.java:14)
...
关键区别总结:
- 堆溢出通常是因为对象存活时间过长或数量过多,需要调整堆大小(
-Xmx)或优化对象引用逻辑。 - 栈溢出通常是代码逻辑问题(如死循环递归),可通过检查递归终止条件或在启动参数中增加栈容量(
-Xss)临时缓解,但根本解决需修复代码逻辑。
以上就是Java内存溢出中堆溢出与栈溢出详细内容的解析,更多关于Java JVM内存管理的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













