全局创建对象触发StackOverflowError而非OutOfMemoryError?附代码疑问
关于Java栈溢出与堆溢出的两个问题解答
问题1:全局创建对象时出现StackOverflowError,为何未触发OutOfMemoryError?
首先得把两个错误的本质掰明白:
- StackOverflowError:是栈内存耗尽引发的,常见场景是方法调用层级过深(比如无限递归),或者实例初始化时陷入无限递归创建对象的死循环。
- OutOfMemoryError(堆内存版):是堆内存无法再分配新对象时才会触发的错误。
当你在全局(比如类的实例变量里直接new自身)创建对象时,会陷入「创建对象→初始化实例变量→再创建对象→再初始化实例变量」的无限递归链。这个过程中,每一次对象初始化都会触发方法调用(比如构造器、实例变量初始化逻辑),而每一次方法调用都会在栈中生成一个新的栈帧。
栈的容量通常远小于堆(栈一般是MB级,堆动辄GB级),所以栈会先被撑爆,直接触发StackOverflowError让程序终止——这时候堆还没来得及积累足够多的对象,自然没机会触发OutOfMemoryError。
问题2:给定代码为何未出现OutOfMemoryError?
先把代码贴出来方便分析:
public class Abc { Abc abc1=new Abc(); static Abc abc=new Abc(); public static void main(String[] args) { Abc abc=new Abc(); } }
咱们一步步拆解执行流程,你就懂了:
- JVM启动后要执行
main方法,首先得加载Abc类。类加载时会初始化静态成员变量abc,也就是执行new Abc()。 - 执行
new Abc()创建实例时,会先初始化非静态成员变量abc1,也就是又调用new Abc()。 - 这个新的
Abc实例创建时,又要初始化它自己的abc1,再次执行new Abc()……这就形成了无限递归的初始化循环。
和第一个问题的核心逻辑一致:每一次初始化操作都会在栈中压入新的栈帧,栈的小容量扛不住这种无限递归,很快就会触发StackOverflowError,程序直接崩溃。堆内存还没来得及分配足够多的对象(甚至可能只创建了几个实例),所以根本到不了触发OutOfMemoryError的地步。
内容的提问来源于stack exchange,提问作者user9558710
相关产品推荐
相关产品推荐

