【问题标题】:Which Java Errors and Exceptions may (not) be thrown by "empty statements"?“空语句”可能(不)抛出哪些 Java 错误和异常?
【发布时间】:2015-02-25 01:36:30
【问题描述】:

java.lang.Throwable 的哪个子类可能会被空语句抛出?

“空语句”一词是指“无”、“分号”和“分号”:

// ....
A(); B(); C();
try {
     // nothing
} catch (java.lang.Throwable e) {
     // which Throwable subclass might we see?
}
D(); E(); F();
try {
     ; // semi-colon
} catch (java.lang.Throwable e) {
     // which Throwable subclass might we see?
}
G(); H(); I();
try {
     ; ; ;;  ;;;;; ; ; ;;; ;; ;; ;; ;; ; ;; ; ;; // ... semi-colons
} catch (java.lang.Throwable e) {
     // which Throwable subclass might we see?
}
J(); K(); L();
// ....

哪些 Throwable 子类可以在A();B(); 之间或C();D(); 之间或F();G(); 之间或I(); 和@ 之间抛出987654336@?

或者更确切地说,哪些 Throwable 子类保证 出现在这些语句之间?


The ones I know so farInternalErrorOutOfMemoryErrorStackOverflowErrorUnknownError

【问题讨论】:

  • 你检查得到的字节码了吗?
  • @MaartenBodewes-owlstead,您可以将问题解读为“哪些 Java 错误和异常可能(不)在 个字节码之间抛出?”它甚至不是null,它是“无”。
  • 呃,除了关键的Errors 我没看到

标签: java operating-system jvm virtual-machine jls


【解决方案1】:

这个问题与您发布的the other question 非常相似。我想我会在这里尝试解决这两个问题。

由于您指的是 JVMS,我假设您正在寻求正式的答案,而正式的答案是您的问题实际上没有意义。 :-)

询问如何 JVM 将执行Java 源代码的sn-p 就像询问数学家正确 计算10+10 的方法。数学家可能会说“如何计算它没有定义”。同样,定义Java sn-p含义的JLS也没有详细说明如何执行它。

所以,首先让我稍微正式化您的问题:“在 字节码(由 javac 的参考实现发出)对应于给定的 Java sn-ps 的位置会出现 VirtualMachineErrors 吗? "

这个问题可以说要简单得多。 relevant section of the JVMS

当内部错误或资源限制阻止它实现本章中描述的语义时,Java 虚拟机实现会抛出一个对象,该对象是类VirtualMethodError 的子类的实例。本规范无法预测可能会遇到内部错误或资源限制的位置,也没有明确规定何时可以报告它们。

因此,答案是:任意两条字节码指令之间。

现在回到你原来的问题:例如这个 sn-p

try {
     // nothing
} catch (java.lang.Throwable e) {
     // which Throwable subclass might we see?
}

编译成空程序,不能合理抛出任何异常。


关于您在评论中的后续问题:

JLS 11.1.3 是否应该被解读为“保证Throwable 的子类不会出现在字节码之间,除非它是VirtualMachineError 的子类”?

是的,你可以这样说。我可能会措辞有点不同:任何指令都可以引起

  • JVM Instruction set 为相关指令指定的异常,
  • VirtualMachineError 类型的任何异常
  • 没有其他例外

【讨论】:

  • 一个程序可能需要一组固定的资源才能运行,即使它是空程序。那么面对运行空程序时的资源限制,抛出VirtualMethodError是正确的行为(根据JVMS)吗?
  • 嗯.. 我必须说我想不出一个正式的答案。 JVM 可能会为空程序抛出VirtualMachineError。奇怪的是,javac 放弃了包含try { } catch (VirtualMachineError e) { ... } 的程序的整个 try/catch 块,所以javac 在这方面不是 100% 正式的,或者规范中有一些我不理解的东西。
【解决方案2】:

编译器可能会从字节码中删除包含“无”或空语句的代码。字节码中的等价物将完全类似于:

// ....
A(); B(); C();

D(); E(); F();

G(); H(); I();

J(); K(); L();
// ....

当然,在执行过程中,任何类型的意外Error(如UnknownError)都可能发生,并且通常不会在您的应用程序中处理它。

任何地方可能发生的最接近的异常类型(强调是为了可能涵盖两个字节码指令之间的时间)是asynchronous exceptions

大多数异常是同步发生的,因为它们发生在线程中,并且在程序中指定可能导致此类异常的某个点处发生。相比之下,异步异常是在程序执行的任何时候都可能发生的异常。

异步异常仅由于以下原因而发生:

  • 调用ThreadThreadGroup 类的(已弃用)stop 方法。

    (已弃用)stop 方法可能由一个线程调用以影响另一个线程或指定线程组中的所有线程。它们是异步的,因为它们可能发生在其他线程或线程执行的任何时候。

  • Java 虚拟机中的内部错误或资源限制阻止它实现 Java 编程语言的语义。在这种情况下,抛出的异步异常是VirtualMethodError 的子类的一个实例。

但同样,没有必要关心这种类型的异常(VirtualMethodError 的子类),因为它们代表 JVM 执行中的严重错误。例如,可能是由于用户使用 Ctrl+C 手动中断。在这种情况下,您无能为力。

【讨论】:

  • 应该将 JLS 11.1.3 读作“Throwable 的子类保证 出现在字节码之间,除非它是VirtualMethodError 的子类“?
  • @Pacerier 我会把它读作“除非它是一个异步异常”(还有另一个关于异步异常的条件,我已经添加到引用中)......我会读它一粒盐,因为它没有明确解决您的问题。另一方面,我错过了值得一提的一点是我们假设有问题的线程没有阻塞
  • 一定是错字,应该是VirtualMachineError
【解决方案3】:

如果您不执行任何指令,则 VM 不太可能为当前线程请求内存或用完堆栈空间。由于 VM 中的任何一种状态都无法正常运行,因此可能会引发其他异常,我想您应该始终期望 InternalErrorUnknownError 会发生。因此,您不应该抓住Throwable,而是抓住Exception,因为您不太可能从错误中恢复过来——除非您可能正在创建自己的框架。

【讨论】:

  • JVMS是否保证随机线程执行指令不会导致其他线程即使在不执行任何指令时也抛出错误?
  • 我非常怀疑这是一个明确的规则,但我还没有看到任何实现如果你不分配任何空间会抛出这样的错误。一个线程要求 2 Gi 的 long[] 并且这个异常被抛出到另一个线程上?不。
猜你喜欢
  • 1970-01-01
  • 2014-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-21
  • 1970-01-01
  • 2015-12-19
相关资源
最近更新 更多