实际导致堆栈溢出错误的原因是什么?

2022-08-31 05:44:58

我到处寻找,找不到一个可靠的答案。根据文档,Java 在以下情况下会抛出 java.lang.StackOverflowError 错误:

当堆栈溢出由于应用程序递归太深而发生时引发。

但这提出了两个问题:

  • 难道没有其他方法可以发生堆栈溢出,而不仅仅是通过递归吗?
  • StackOverflowError 是在 JVM 实际溢出堆栈之前还是之后发生的?

详细阐述第二个问题:

当Java抛出StackOverflowError时,你能安全地假设堆栈没有写入堆吗?如果您在引发堆栈溢出的函数的 try/catch 中缩小堆栈或堆的大小,是否可以继续工作?这在任何地方都有记录吗?

我不寻找的答案:

  • 堆栈溢出的发生是由于递归不良。
  • 堆栈溢出在堆与堆栈相遇时发生。

答案 1

您似乎认为堆栈溢出错误类似于本机程序中的缓冲区溢出异常,当存在写入尚未分配给缓冲区的内存的风险,从而损坏其他一些内存位置时。事实并非如此。

JVM 为每个线程的每个堆栈分配了一个给定的内存,如果尝试调用某个方法碰巧填满了此内存,JVM 就会引发错误。就像你试图在长度为N的数组的索引N处写入一样。不会发生内存损坏。堆栈无法写入堆。

StackOverflowError对堆栈来说就像OutOfMemoryError对堆一样:它只是发出信号,表明没有更多的内存可用。

虚拟机错误 (§6.3) 中的说明

StackOverflowError:Java 虚拟机实现的堆栈空间已耗尽,这通常是因为由于执行程序中的错误,线程正在执行无限数量的递归调用。


答案 2

难道没有其他方法可以发生堆栈溢出,而不仅仅是通过递归吗?

确定。只需继续调用方法,而无需返回。但是,您需要很多方法,除非您允许递归。实际上,这并没有区别:堆栈帧是堆栈帧,它是否是递归方法之一是相同的。

第二个问题的答案是:当 JVM 尝试为下一个调用分配堆栈帧时,检测到堆栈溢出,并发现这是不可能的。因此,任何内容都不会被覆盖。


推荐