关于虚拟机异常处理中的"异常"

simpleman7210 2013-11-08
我最近被一个问题困扰了,是虚拟机异常处理过程中的一个问题。通常当执行某个Java指令,虚拟机检测到错误时,虚拟机就主动抛出异常,并处理此异常。为此虚拟机要先生成一个异常实例,然后抛出并处理之。我的问题不是抛出和处理环节,而是在异常实例生成的时候。倘若在生成异常实例的时候遇到麻烦怎么办?比如,new实例出错。即使new成功,虚拟机接着要执行其<init>方法吧?如果在执行<init>方法时遇到异常(未处理)被抛出....这就是困难的地方了,倘若异常实例都不能正常生成,接下来的抛出和处理如何谈起呢。究竟要如何面对这种异常实例生成中的"异常"?
RednaxelaFX 2013-11-08
JVM实现里通常会在每个Java线程上记一个flag,叫做pending exception。如果VM执行到某个操作需要抛异常,就把pending exception设上值,等这个异常被正确抛出时再清除掉pending exception的值。
如果要抛异常这个动作本身出了问题无法完成(例如剩余内存不足以创建新的Exception实例),而且pending exception已经不是空的,那就直接退出程序而不再尝试向Java层抛出异常。这样很直观吧?

也可以在JVM初始化时先分配一个InternalError实例,然后遇到某些异常无法处理时抛出这个事先分配的实例。这样看起来更友善些。
simpleman7210 2013-11-09
在JVM初始化的时间分配一个InternalError实例,我原先差不多也是这样处理的。我是在JVM初始化的时候创建两个实例,一个OutOfMemoryError实例,一个Error实例。但是这样做仍遇到同样的问题。这是由于,Error和Error子类是用Java写的,当虚拟机要创建Error或其子类的实例时,除了为异常实例申请内存之后,还要遵循Java中的一般规则,调用其构造函数<init>,甚至类的初始化方法<clinit>。这样我仍要考虑在这个过程发生异常的情况...比较麻烦。所以,现在我是做了简化处理的:JVM初始化时不去构造Error或Error子类的预留实例了。运行时若遇到异常实例创建中的"异常",就标记下,将当前方法调用链中的方法都弹出栈,随后将根据标记把异常抛出去(如果已到顶,程序将退出)。只是有些遗憾,因为程序中若有捕捉异常处理,比如catch Error,甚至catch Throwable,当异常中的"异常"出现时,却没有机会捕捉到并处理了。
Global site tag (gtag.js) - Google Analytics