“抛出新的ZygoteInit.MethodAndArgsCaller”如何清理堆栈帧?

时间:2015-11-10 03:59:07

标签: java android

我是Java和Android的初学者,在阅读Zygote init代码后我感到困惑。

Zygote在invokeStaticMain结尾处分配一个子进程后,它会抛出一个

throw new ZygoteInit.MethodAndArgsCaller(m, argv)

ZygoteInit.main由执行子进程工作的catch块处理

catch (MethodAndArgsCaller caller) {
    caller.run();
}

throw new ZygoteInit.MethodAndArgsCaller的评论说它会清理设置过程所需的所有堆栈帧。

但我无法弄清楚堆栈帧是如何清理的。我检查了相关的SO问题,What are ZygoteInit calls?,但问题和答案都没有解释清理工作。

异常会导致堆栈回收工作吗?

1 个答案:

答案 0 :(得分:6)

有用的背景资料

在Java中,如果方法通过执行return语句完成,或者通过成功执行声明为void的方法的最后一行,则说明正常完成

当方法正常完成时,JVM(Java虚拟机)弹出返回方法的堆栈帧,并在调用方法中的方法调用之后继续执行。调用方法成为当前方法,其堆栈帧成为当前帧。

如果某个方法抛出异常但它没有捕捉到它自己,那么就会说突然完成。突然完成的方法不会返回值,尽管它们会传递异常对象,例如java.io.IOException

当一个方法突然完成时,意味着它抛出了一个它没有捕获到它的异常,JVM会弹出该方法的堆栈帧。然后,JVM检查调用堆栈中的下一个方法,以获取处理抛出异常的catch子句。这个循环一直持续到两件事之一发生:

  1. 找到具有正确catch子句的方法,其中JVM将 使该方法的堆栈帧为当前并继续执行 catch子句中的第一个陈述。

  2. JVM将检查调用堆栈上的public static void main(String[] args),当它找不到正确的catch子句时,它将弹出main的堆栈帧。调用堆栈现在为空,因为main是线程调用的第一个方法。这会导致未捕获异常,该异常将由默认处理程序处理,并导致线程死亡。在大多数JRE(Java运行时环境)中,未捕获异常的默认处理程序将在线程死亡时打印出堆栈跟踪。

  3. 特定于您问题的信息

    异常或突然完成的方法可用于控制程序的流程。虽然99.99%的时间使用控制流异常被视为反模式,但仍有0.01%的时间可能需要或可能大幅改进程序。

    在整个com.android.internal.os.ZygoteInit课程中可以看到使用异常作为控制流程。主要通过使用以下例外:

    /**
     * Helper exception class which holds a method and arguments and
     * can call them. This is used as part of a trampoline to get rid of
     * the initial process setup stack frames.
     */
    public static class MethodAndArgsCaller extends Exception
           implements Runnable { ... }
    

    当方法的文档说明"这被用作蹦床的一部分以摆脱初始过程设置堆栈帧。"我相信术语 trampoline 指的是我上面提到的,关于JVM弹出堆栈帧和检查调用堆栈上的方法,直到找到正确的catch子句。蹦床的另一个术语可能是传播。

    到目前为止我发现的唯一一种ZygoteInit.MethodAndArgsCaller例外的方法是ZygoteInit类' main方法,似乎是中央控制。但是,我在com.android.internal.os.RuntimeInit类中发现了许多在声明中有throws ZygoteInit.MethodAndArgsCaller的方法。意思是,这些方法中调用的方法抛出或传播MethodAndArgsCaller异常。谁知道它会走多远?

    我不是Android,Java或Zygote流程的专家,而且我不了解作者,所以我只能根据我研究的内容和Android进行假设源代码。我希望我帮助解决了一些问题,如果需要更多帮助,请告诉我。

    有用的链接