暴力破解美团最新JVM面试题:无限执行( 二 )


咱们先就之前的三段探索得出的经验进行头脑风暴一下:程序无限执行的能力 , Linux没有提供 , 但是这段Java程序能够无限执行 , 说明这个能力是JVM赋予的 。
那JVM如何做到的呢?首先 , 栈的内存大小决定了 , 一个程序的调用深度是有限的 , 超过了栈内存大小 , Linux会触发段错误信号:SIGSEGV 。JVM应该是捕获了这个信号 , 并进行了处理 。那什么样的处理能支持程序一直运行下去呢?如果你理解了刚刚那个栈图你就清晰了 , 一定是做了栈帧回溯 。
最终结论是:JVM捕获了段错误信号并做了处理 , 处理方式是栈帧回溯 。接下来我只贴核心代码 , 有能力研究Hotspot源码的可以去自行研究 。当然 , 我的结论不一定就是百分百正确的 , 如果你有不一样的结论并完成了论证 , 欢迎找我交流 。
这里面还有个知识点我跳过了 , 我提一下 , 感兴趣的自己去研究:yellow zone、red zone、glibc guard
 
JVM捕获了异常 , 并为此创建了执行流

暴力破解美团最新JVM面试题:无限执行

文章插图
 
研究这个执行流一直往后面追 , 最终会追到这里
暴力破解美团最新JVM面试题:无限执行

文章插图
【暴力破解美团最新JVM面试题:无限执行】 
之前说的1024是怎么来的 , 就是MaxJavaStackTraceDepth的值 。JVM默认支持的栈最大深度就是1024 。为什么是1024 , 因为触发异常的时候需要遍历栈 , 导出栈信息 , 如果栈的深度很深 , 很费时间费性能 , 就取了一个有象征意义的值 。
 
1024也是一个临界点 , 当栈深度达到1024 , 栈帧开始回溯 。你可以理解成程序跑起来把栈深度冲到1024 , 开始回溯 , 回溯到初始调用时的栈 , 然后栈深度又开始冲1024 , 循环往复
暴力破解美团最新JVM面试题:无限执行

文章插图
 
解释执行时是这样干的 , 那JIT编译又做了哪些优化呢?
05最终探索
针对回调做优化 , 目前主流的优化方式有:尾递归优化、内联优化 。JVM没有用尾递归优化 , 而是用的内联优化 , 专业名词叫递归内联 。
此结论来自之前看的R大的某篇文章 。本来想找到贴出来的 , 没找着 。有贴心的小伙伴找着了可以发给我 , 我贴出来 。
到这里 , 这个问题就探索得无比清晰了 。撒花~
作者:五角钱的程序员
原文链接:
https://mp.weixin.qq.com/s/BKq6dbkUbKtVEFhQDyK5ag




推荐阅读