我是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?,但问题和答案都没有解释清理工作。
异常会导致堆栈回收工作吗?
答案 0 :(得分:6)
在Java中,如果方法通过执行return
语句完成,或者通过成功执行声明为void
的方法的最后一行,则说明正常完成强>
当方法正常完成时,JVM(Java虚拟机)弹出返回方法的堆栈帧,并在调用方法中的方法调用之后继续执行。调用方法成为当前方法,其堆栈帧成为当前帧。
如果某个方法抛出异常但它没有捕捉到它自己,那么就会说突然完成。突然完成的方法不会返回值,尽管它们会传递异常对象,例如java.io.IOException
。
当一个方法突然完成时,意味着它抛出了一个它没有捕获到它的异常,JVM会弹出该方法的堆栈帧。然后,JVM检查调用堆栈中的下一个方法,以获取处理抛出异常的catch子句。这个循环一直持续到两件事之一发生:
找到具有正确catch子句的方法,其中JVM将 使该方法的堆栈帧为当前并继续执行 catch子句中的第一个陈述。
JVM将检查调用堆栈上的public static void main(String[] args)
,当它找不到正确的catch子句时,它将弹出main
的堆栈帧。调用堆栈现在为空,因为main
是线程调用的第一个方法。这会导致未捕获异常,该异常将由默认处理程序处理,并导致线程死亡。在大多数JRE(Java运行时环境)中,未捕获异常的默认处理程序将在线程死亡时打印出堆栈跟踪。
异常或突然完成的方法可用于控制程序的流程。虽然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进行假设源代码。我希望我帮助解决了一些问题,如果需要更多帮助,请告诉我。