***Error 啥时候发生? [复制]
Posted
技术标签:
【中文标题】***Error 啥时候发生? [复制]【英文标题】:When does ***Error occur? [duplicate]***Error 什么时候发生? [复制] 【发布时间】:2014-01-06 15:19:14 【问题描述】:根据 Oracle 的说法,***Error 是:
由于应用程序递归太深而发生堆栈溢出时引发。
我知道什么是递归,通常递归函数,如果没有正确终止,会导致 ***Error。为了检查在***Error
被抛出之前发生的递归调用的数量,我编写了以下代码:
package ErrorCases;
public class ***Error
static int i=0;
void a()
//System.out.println("called "+(++i));
try
++i;
a();
catch(Error e)
System.out.println(e.getClass());
System.out.println(i);
public static void main(String[] args)
new ***Error().a();
i
的值给出了在 JVM 抛出 ***Error 之前对 a()
的递归调用计数。i
的值在每次运行中都不同,例如:
output 1: class java.lang.***Error
10466
Output 2: class java.lang.***Error
10470
我的查询是?
在 JVM 抛出之前,递归必须发生多深
***Error
?
一旦***Error
有
被扔了?
【问题讨论】:
从堆栈溢出中恢复需要完全禁欲——哎呀,我的意思是非常不确定。如果代码当时正在进行一些复杂的操作,则可能没有足够的堆栈空间允许它退出。并且许多正在进行的操作可能无法防止此类故障,并且根本无法退出/重置。 我读了很长时间的最佳问题。让我思考!谢谢 【参考方案1】:深度取决于两件事:
1:栈的大小。
2:每次递归使用的堆栈空间量。
函数参数、局部变量和返回地址都在栈上分配,对象在堆上分配。
恢复
有可能恢复。
try
myDeepRecursion();
catch (***Error e)
// We are back from deep recursion. Stack should be ok again.
但是,请注意以下有关错误的信息(来自 java API 文档):
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.
编辑:
注意事项:虽然在递归函数中捕捉异常是可以的,但不要试图捕捉错误。如果堆栈已满,则错误处理将导致新的错误。简单的事情,例如对System.out.println()
的调用将失败,因为堆栈上没有空间用于返回地址。
这就是为什么错误应该在递归函数之外被捕获。
【讨论】:
我们可以控制深度吗? 你可以使用 jvm 选项 -Xss 解释here ***.com/questions/3700459/… 不是来自外部。 JVM 没有“maxRecursionDepth”参数。但是,您可以使用-Xss
JVM 参数指定堆栈大小。
在我的回答中添加了一个编辑。【参考方案2】:
在 JVM 抛出 ***Error 之前,递归必须发生多深?
这实际上取决于您正在使用的机器以及您的 JVM 及其配置。 (在我当前的设置中是 6000 - 8500,在后台有很多任务),最多是你在应用程序和递归方法中执行的操作。
一旦 ***Error 被抛出,我们可以恢复吗?
不!我Java抛出一个错误,没有办法恢复正常。这是异常和错误之间的主要区别。
错误是 Throwable 的子类,表示合理的应用程序不应尝试捕获的严重问题
Read more about Errors here
Read more about Java stack size myths here
编辑:
发生错误后你仍然可以做事,但这有意义吗?您的代码中有严重错误!您无法确定一切正常!
您的代码没有终止,因为您再次调用该方法,这就像一个无限循环一样
【讨论】:
他们为什么每次运行时输出显示不同的值?我在同一台机器上运行 基本上是的。计算机是一台工作机器,有或多或少的事情要做 在catch(Error e),
调用其他函数,如果栈满了,它是怎么工作的?
请检查编辑。
请检查第二个代码。它没有终止。它是如何打印堆栈的?【参考方案3】:
您可能会看到不同的堆栈深度的原因是堆栈帧的大小不一定相同。例如,Hotspot JVM 对 JIT 编译代码和解释代码有不同的堆栈帧。 JIT 编译器与正在运行的代码并行工作,因此机器上的负载等外部因素可能会影响 JVM 何时/是否开始使用 JIT 堆栈帧。
您应该记住的一件事是,当您获得***Error
时,几乎您所做的任何事情都可能导致另一个***Error
。例如在catch
部分打印错误类的名称也可能会用完堆栈空间,因此另一个***Error
将被扔下堆栈。
有些人声称您无法从Error
中恢复,因为 JVM 正在关闭。这是不正确的;您可以从一些错误中恢复。 ***Error
和 OutOfMemoryError
的棘手之处在于,一旦你抓住了一个,你就绝对不能保证程序的状态。例如,您使用的关键数据结构可能处于不一致的状态。这通常会使恢复变得困难或不可能。
【讨论】:
感谢您的回答,如果***Error
表示“没有剩余堆栈”?为什么我可以从catch()
内部调用函数b()
?
抛出错误时,从堆栈中移除最顶层的帧,并由调用方法中的catch
块处理错误。如果没有足够的堆栈空间,则会抛出另一个 ***Error
并删除另一个框架。这个过程一直持续到删除了这么多帧,以至于 catch 块可以完成而不会引发错误。【参考方案4】:
参数和局部变量在堆栈上分配(对象存在于堆上的引用类型和引用该对象的变量)。堆栈通常位于地址空间的上端,当它用完时,它会朝向地址空间的底部(即朝向零)。
您的进程也有一个堆,它位于进程的底部。当你分配内存时,这个堆会增长到地址空间的上端。如您所见,堆有可能与堆栈“碰撞”(有点像技术板!!!)。 [source]
因此 StackOIverflowError 将取决于您的堆栈大小以及堆大小,由于 GC 等许多因素,堆栈大小将取决于执行与执行。
正如名字所说,它是错误而不是异常。没有任何恢复。 JVM 将关闭。
【讨论】:
谢谢,但是如果JVM关闭了,那我们怎么catch
它运行代码呢?
只有在没有捕捉到错误的情况下,JVM才会关闭。
Exception
也一样,那么,从这个意义上讲,Exception
如果不处理,会导致JVM崩溃。
但是捕获的异常应该被处理,未捕获的异常在某些情况下根本没有错误。
如果你在 Throwable 一直“冒泡”之前捕获它,它不会关闭 JVM。如果你没有抓住它,它会的。这适用于所有 Throwable,无论是异常还是错误。不同之处在于一个人应该对它们做什么,这总是需要谨慎对待。以上是关于***Error 啥时候发生? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
Objective-C 中的“&error”是啥意思? [复制]