异常是怎么被处理的?这题的答案不在源码里面。 (上)

简介: 异常是怎么被处理的?这题的答案不在源码里面。 (上)

image.png

他是看了我《神了!异常信息突然就没了?》这篇文章后产生的疑问。

既然是看了我的文章带来的进一步思考,恰巧呢,我又刚好知道。

虽然这类文章看的人少,但是我还是来填个坑。

害,真是暖男石锤了。


image.png


异常怎么被抛出的。


先上一个简单代码片段:

image.png

运行结果大家都是非常的熟悉。

光看这仅有的几行代码,我们是探索不出来什么有价值的东西。

我们都知道运行结果是这样的,没有任何毛病。

这是知其然。

那么所以然呢?

所以然,就藏在代码背后的字节码里面。

通过 javap 编译之后,上面的代码的字节码是这样:

image.png

我们主要关注下面部分,字节码指令对应的含义我也在后面注释一下:

public static void main(java.lang.String[]);
    Code:
       0: iconst_1 //将int型的1推送至栈顶
       1: iconst_0 //将int型的0推送至栈顶
       2: idiv     //将栈顶两int型数值相除并将结果压入栈顶
       3: istore_1 //将栈顶int型数值存入第二个本地变量
       4: return   //从当前方法返回 void

别问我怎么知道字节码的含义的,翻表就行了,这玩意谁背得住啊。

通过字节码,好像也没看出什么玄机来。

但是,你先记着这个样子,马上我给你表演一个变形:

public class MainTest {
    public static void main(String[] args) {
        try {
            int a = 1 / 0;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

用 try-catch 把代码包裹起来,捕获一下异常。

再次用 javap 编译之后,字节码变成了这个样子:

可以明显的看到,字节码发生了变化,至少它变长了。

主要还是关注我框起来的部分。

把两种情况的字节码拿来做个对比:

对比一下就很清楚了,加入 try-catch 之后,原有的字节码指令一行不少。

没有被框起来的,就是多出来的字节码指令。

而多出来的这部分,其中有个叫做 Exception table 尤为明显

image.png

异常表,这个玩意,就是 JVM 拿来处理异常的。

至于这里每个参数的含义是什么,我们直接绕过网上的“二手”资料,到官网上找文档:

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.3


image.png

看起来英文很多,很有压力,但是不要怕,有我呢,我挑关键的给你 say:


image.png


首先 start_pc、end_pc 是一对参数,对应的是 Exception table 里面的 from 和 to,表示异常的覆盖范围。

比如前面的 from 是 0 ,to 是 4,代表的异常覆盖的字节码索引就是这个范围:

0: iconst_1 //将int型的1推送至栈顶
1: iconst_0 //将int型的0推送至栈顶
2: idiv     //将栈顶两int型数值相除并将结果压入栈顶
3: istore_1 //将栈顶int型数值存入第二个本地变量

有个细节,不知道你注意到了没有。

范围不包含 4,范围区间是这样的 [start_pc, end_pc)。

而至于为什么没有包含 end_pc,这个就有点意思了。

拿出来讲讲。

The fact that end_pc is exclusive is a historical mistake in the design of the Java Virtual Machine: if the Java Virtual Machine code for a method is exactly 65535 bytes long and ends with an instruction that is 1 byte long, then that instruction cannot be protected by an exception handler. A compiler writer can work around this bug by limiting the maximum size of the generated Java Virtual Machine code for any method, instance initialization method, or static initializer (the size of any code array) to 65534 bytes.

不包含 end_pc 是 JVM 设计过程中的一个历史性的错误。

因为如果 JVM 中一个方法编译后的代码正好是 65535 字节长,并且以一条 1 字节长的指令结束,那么该指令就不能被异常处理机制所保护。

编译器作者可以通过限制任何方法、实例初始化方法或静态初始化器生成的代码的最大长度来解决这个错误。

上面就是官网的解释,反正就是看的似懂非懂的。

没关系,跑个例子就知道了:

image.png

当我代码里面只有一个方法,且长度为 16391 行时,编译出来的字节码长度为 65532。

而通过前面的分析我们知道,一行 a=1/0 的代码,会被编译成 4 行字节码。

那么只要我再加一行代码,就会超出限制,这个时候再对代码进行编译,会出现什么问题呢?

看图:


image.png


直接编译失败,告诉你代码过长。

所以你现在知道了一个知识点:一个方法的长度,从字节码层面来说是有限制的。但是这个限制算是比较的大,正常人是写不出这样长度的代码的。

虽然这个知识点没啥卵用,但是要是你在工作中真的碰到了一个方法长度成千上万行,即使没有触发字节码长度限制,我也送你一个字:快跑。


image.png

接着说下一个参数 handler_pc,对应的是 Exception table 里面的 target。

其实它非常好理解,就是指异常处理程序开始的那条指令对应的索引。

比如这里的 target 是 7 ,对应的就是 astore_1 指令:

image.png



目录
相关文章
|
并行计算 Java 数据处理
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
1074 0
vscode点击通过import引入方法名或模块名跳转其定义的文件
window点击ctrl(MAC点击command)+通过import引入的文件、方法等到,跳转到其定义的页面
1621 0
|
8月前
|
缓存 NoSQL Java
【📕分布式锁通关指南 11】源码剖析redisson之读写锁的实现
Redisson 的 `RedissonReadWriteLock` 提供了高效的分布式读写锁实现,适用于读多写少的场景。通过 Redis 与 Lua 脚本结合,确保读锁并行、写锁互斥,以及读写之间的互斥,保障了分布式环境下的数据一致性。它支持可重入、自动过期和锁释放机制,提升了系统并发性能与资源控制能力。
191 0
|
10月前
|
人工智能 Java API
Spring AI 实战|Spring AI入门之DeepSeek调用
本文介绍了Spring AI框架如何帮助Java开发者轻松集成和使用大模型API。文章从Spring AI的初探开始,探讨了其核心能力及应用场景,包括手动与自动发起请求、流式响应实现打字机效果,以及兼容不同AI服务(如DeepSeek、通义千问)的方法。同时,还详细讲解了如何在生产环境中添加监控以优化性能和成本管理。通过Spring AI,开发者可以简化大模型调用流程,降低复杂度,为企业智能应用开发提供强大支持。最后,文章展望了Spring AI在未来AI时代的重要作用,鼓励开发者积极拥抱这一技术变革。
3405 71
Spring AI 实战|Spring AI入门之DeepSeek调用
|
9月前
|
JSON 供应链 API
商品条码查询 API 实战指南:掌握商品“唯一身份标识”
商品条码查询API简介:基于1974年诞生的条码技术,该API通过输入13/14位条码,快速获取商品基本信息(名称、品牌、规格等)和成分信息(营养成分、配料表等)。其核心功能包括商品条码查询接口与成分查询接口,广泛应用于零售、电商、物流及健康饮食等领域。支持HTTP POST请求,提供便捷的代码调用示例。作为数字化转型的重要工具,它不仅方便消费者查询商品详情,还助力商家优化库存管理与销售流程,提升运营效率。
2208 3
r语言中对LASSO回归,Ridge岭回归和Elastic Net模型实现
r语言中对LASSO回归,Ridge岭回归和Elastic Net模型实现
|
Java Spring
SpringBoot+async异步调用接口以及几个任务同时完成和异步接口实现和调用
SpringBoot+async异步调用接口以及几个任务同时完成和异步接口实现和调用
885 0
AutoJs4源代码分享---十大高收益合集
AutoJs4源代码分享---十大高收益合集
277 0
pytest添加自定义参数
pytest添加自定义参数
848 0

热门文章

最新文章