是否只是在每次完成除法时检查除数是否与零不同(即使在JIT编码中)?
我的意思是VM如何在没有被操作系统杀死的情况下设法抛出异常?
答案 0 :(得分:32)
在Unix环境中,signal
通过SIGFPE
引导除零,JVM将安装一个信号处理程序,用于捕获SIGFPE
并依次throw
1}}是ArithmeticException
。如果您对内部感兴趣,请参阅例如man signal
我认为OP所要求的是基于以下事实:除非SIGFPE
处理程序到位,否则大多数进程将采取默认操作来接收此信号,即终止。因此,例如,一个C程序
int main (int argc, char** argv) { int n = 5 / 0; }
...如果它甚至编译,将被默认的SIGFPE
→SIG_DFL
操作杀死。相反,JVM的处理程序会发出(catch
)RuntimeException
,以便可以以原生的方式处理这些异常。
正如其他几个人指出的那样,只是为了完整性,事实上从内核生成的SIGFPE
通常是从处理器本身的特殊中断映射的;因此,“管道”就像
SIGFPE
SIG_DFL
→处理死亡或
SIGFPE
处理程序→用户代码中的RuntimeException
ArithmeticException
在非Unix平台上,处理类似。
答案 1 :(得分:7)
Java像任何其他语言一样处理这种情况。除以零错误会产生处理器异常,从而触发中断。操作系统“读取”中断,并在注册处理程序时将其转发给程序。由于Java注册了一个处理程序,它会收到错误,然后将其转换为在堆栈中向上移动的ArithmeticException
。
答案 2 :(得分:6)
JVM使用C:
像这样捕获除零#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
void fpe_handler(int signum) {
printf("signal is %d", signum);
printf("JVM throws an ArithmeticException here...\n");
exit (1);
}
int main() {
int a = 5;
int b = 0;
signal(SIGFPE, fpe_handler);
printf("%d\n", a / b);
return 0;
}
编译并运行它打印出来:
el@apollo:~$ gcc -o catch_sigfpe myc.c
el@apollo:~$ ./catch_sigfpe
signal is 8
JVM throws an ArithmeticException here...
el@apollo:~$
操作系统同步引发SIGFPE异常,C程序捕获它,然后java构造并向您提供ArithmeticException并自行清理以停止Java程序。
答案 3 :(得分:2)
OS向进程发送信号。默认处理程序将停止进程,但您可以为它定义自己的处理程序。我打赌java VM会这样做。