在这个专栏的 第一期,我们讨论了抛出异常的开销。这个月,我们换一个角度再来看这个主题 ―― JVM 如何处理所抛出的异常 ―― 并且我们要考虑,最理想的异常编码应该看成是早期的优化还是最优方法?
编码的艰难决择:应该这样做还是那样做?
性能讨论组中充斥着类似于这样的问题“我应该像大多数人那样编写代码,还是为了得到更好的性能那样编写代码?”一般专家会建议应该避免早期的优化,并且直到性能测试显示需要优化的时候才使用最优方法,但实际情况是我们每写一行代码都在做出会影响到性能的决定。
JavaRanch 上的一项讨论调查了确保类型安全的两种选择,一种是抛出异常,另一种是用 instanceof ,并提出了“哪种方法更好”的问题。清单 1 和 2 显示了这两种方法。
清单 1. 使用 instanceof 来分支
Listing 1: using instanceof to branch
for (int i = 0; i < max; i++)
{
Object obj = myVector.elementAt(i);
if (obj instanceof MySpecialClass)
{
// do this
}
}
清单 2. 抛出异常来分支
for (int i = 0; i < max; i++) {
try {
MySpecialClass myClass = (MySpecialClass)myVector.elementAt(i);
// do this
} catch (ClassCastException cce) {
continue; // for loop
}
}
提这种问题的危险之一是,当您想把问题浓缩成一个简单例子时可能会失去很多上下文。没有充分的上下文通常会把讨论弄得长而混乱,因为每一个阅读了问题的回答者都会用他们自己的上下文来联系问题。所有这种额外的上下文都会增添含义,这会把我们从问题的出发点转移出来。头脑里有了这些东西之后,就让我们来看能否从这一思路中找到的消息线索中筛选出某些真理来。
异常的特征
提起异常大多数开发者首先要说的就是它们很昂贵。如果您继续追问为什么它们很昂贵,最普遍的答案是我们需要捕获异常堆栈的当前状态。尽管这是开销的很大一部分,但通过列出异常的一些特征,我们可以知道这只是故事的开始。下面是异常的一些特征:
* 可以被抛出。
* 可以被捕获。
* 可以被程序化地创建。
* 可以被 JVM 创建。
* 被表示为第一级对象。
* 继承的深度从 3 开始。
* 由 String (和来自 1.4 的 StackTraceElement s)组成。
* 依靠本机方法 fillInStackTrace() 。
异常与其他对象的主要区别是异常可以被抛出和捕获。让我们从调查当异常被抛出时所触发的事件过程来开始我们的研究。
处理异常的开销
为了抛出异常,JVM 发出 athrow 字节码指令。 athrow 指令引起 JVM 将异常对象弹出执行堆栈。然后 JVM 搜索当前执行堆栈帧来寻找第一个 catch 子句,这个子句可以处理该类的一个异常或者其超类的一个异常。如果在当前的堆栈帧里没有找到 catch block ,那么当前堆栈帧就被释放,异常在下一个堆栈帧的上下文中被重新抛出,如此这般,直到找到包含匹配的 catch 子句的堆栈帧,或者是到了执行堆栈的底部。最后,如果没找到适当的 catch 块,所有的堆栈帧都会被释放,线程在 ThreadGroup 对象有了处理异常的机会后被终止(参考 ThreadGroup.uncaughtException )。如果找到了适当的 catch 块,程序计数器会重置到那一块代码的第一行。
从这个描述中我们可以了解到处理一个抛出的异常是一个非常昂贵的主张。再看一看上面的异常特征清单。注意到除了 JVM 可以“本能地”创建一个异常外,其余剩下的开销与在任何其他第一级对象的生命周期中所引起的开销没有什么区别。
异常作为第一级对象的开销
现在回忆一下 清单 2。只有当强制转换失败的时候异常才被抛出。JVM 是如何处理它的呢?当一个应用需要进行强制类型转换的时候,一个 checkcast 操作就会被发出。这项操作只用于保证堆栈顶部的参数类型是预期的。如果不是预期的,它就会抛出一个 ClassCastException 。
类型检查文雅的做法是使用如 清单 1 所示的 instanceof 操作符。 checkcast 和 instanceof 的区别之一是后者会在堆栈的顶部保留 0 或 1 来表失败或成功。
instanceof 操作符遵循非常严格的一组规则来决定成功或失败。无论变量引用是不是 null 、数组、接口或者类,规则都需要重视。一旦确定了变量的类型,就必须搜索另一边的合格操作数的层次,直到找到匹配的类型或者到达层次的结尾。在数组的情况中,基本元素的类型也也必须经过同样的审查。
除了这项开销外,一旦用了 instanceof ,您就要在后面的代码里将对象进行强制类型转换。执行后继类型转换会导致 checkcast 字节码的执行。所以用于确定类型转换是否工作的逻辑可能会被重复(假设 JVM 没有优化额外的检查)。虽然如此,但因为使用 instanceof 操作符不需要创建新的对象,所以从内存资源和执行资源方面考虑,比起创建和处理异常来说它是廉价得多的操作。那么最初问题的答案就很明显了,对吗?
隐藏的风险
捕获 ClassCastException 同样存在隐藏的风险,也就是说我们可能会捕获从取代了“这样做”注释的代码中抛出的 ClassCastException 。如果该代码在一些操作的中间抛出 ClassCastException ,那么我们可以捕获到它,如果它来自对 MySpecialClass 的强制类型转换,并被忽略,就可能使应用程序处于不一致的状态。
动态调优
到目前为止,我们所做的只是评估了所提到的两种编码风格中每一种一次性执行的开销。现在我们需要了解代码将被执行的条件,以便确定应该使用哪种编码风格。
考虑迭代一个集合的情况,以了解实际花费的开销。如果集合包括同质的一组对象,并且将在的每一个对象上执行一个 instanceof 操作,过程会把不必要的开销强加在整个运行时间中。另一方面,如果集合包括异类的一组对象,那么我们使用 instanceof 操作会更好,而不会引起强烈的异常开销。
这种情况给了我们最优方法的最终线索:异常应该为异常的情况保留。在异常的情况下使用异常对性能来说是理想的;在无异常的情况下使用检查来避免抛出异常对性能来说也是理想的。
结束语
从所有这些我们可以看到,遵循最优方法(这里是指异常应该用于异常的情况下)可以产生更好的性能。有的时候我们需要全面考虑类似于这篇文章里所说的情景来决定最优方法到底是什么,以及最优方法在性能上考虑了什么和它的可选方案。但是现在不用担心过早地优化代码,我们以最好的编码实践结束,它有着适当的独立性能,也提供了优化的性能 ―― 在两方面都是最好的。
转自http://www.ibm.com/developerworks/cn/java/j-perf02104/
分享到:
相关推荐
本文详细介绍了PHP的基本语法、变量类型、运算符号以及文件上传和发邮件功能的实现方法,适合初学者了解和掌握PHP的基础知识。
公司金融整理的word文档
Prometheus Python客户端Prometheus的官方 Python 客户端。安装pip install prometheus-client这个包可以在PyPI上找到。文档文档可在https://prometheus.github.io/client_python上找到。链接发布发布页面显示项目的历史记录并充当变更日志。吡啶甲酸
DFC力控系统维护及使用
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
2019-2023GESP,CSP,NOIP真题.zip
博文链接 https://blog.csdn.net/weixin_47560078/article/details/127712877?spm=1001.2014.3001.5502
包含: 1、jasminum茉莉花 2、zotero-style 3、greenfrog 4、zotero-reference 5、translate-for-zotero 用法参考:https://zhuanlan.zhihu.com/p/674602898
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
python技巧学习.zip
2023 年“泰迪杯”数据分析技能赛 A 题 档案数字化加工流程数据分析 完整代码
echarts 折线图数据源文件
Visual Studio Code 的 Python 扩展Visual Studio Code 扩展对Python 语言提供了丰富的支持(针对所有积极支持的 Python 版本),为扩展提供了访问点,以无缝集成并提供对 IntelliSense(Pylance)、调试(Python 调试器)、格式化、linting、代码导航、重构、变量资源管理器、测试资源管理器等的支持!支持vscode.devPython 扩展在vscode.dev (包括github.dev )上运行时确实提供了一些支持。这包括编辑器中打开文件的部分 IntelliSense。已安装的扩展Python 扩展将默认自动安装以下扩展,以在 VS Code 中提供最佳的 Python 开发体验Pylance - 提供高性能 Python 语言支持Python 调试器- 使用 debugpy 提供无缝调试体验这些扩展是可选依赖项,这意味着如果无法安装,Python 扩展仍将保持完全功能。可以禁用或卸载这些扩展中的任何一个或全部,但会牺牲一些功能。通过市场安装的扩展受市场使用条款的约束。可
Centos6.x通过RPM包升级OpenSSH9.7最新版 升级有风险,前务必做好快照,以免升级后出现异常影响业务
5 总体设计.pptx
Python 版 RPAv1.50 • 使用案例• API 参考 • 关于 和制作人员 • 试用云 • PyCon 视频 • Telegram 聊天 • 中文 • हिन्दी • 西班牙语 • 法语 • বাংলা • Русский • 葡萄牙语 • 印尼语 • 德语 • 更多..要为 RPA(机器人流程自动化)安装此 Python 包 -pip install rpa要在 Jupyter 笔记本、Python 脚本或交互式 shell 中使用它 -import rpa as r有关操作系统和可选可视化自动化模式的说明 -️ Windows -如果视觉自动化有故障,请尝试将显示缩放级别设置为推荐的 % 或 100% macOS -由于安全性更加严格,请手动安装 PHP并查看PhantomJS和Java 弹出窗口的解决方案 Linux -视觉自动化模式需要在 Linux 上进行特殊设置,请参阅如何安装 OpenCV 和 Tesseract Raspberry Pi - 使用此设置指南在 Raspberry Pies(低成本自
原生js识别手机端或电脑端访问代码.zip
浏览器
内容概要:本文介绍了基于Spring Boot和Vue开发的旅游可视化系统的设计与实现。该系统集成了用户管理、景点信息、路线规划、酒店预订等功能,通过智能算法根据用户偏好推荐景点和路线,提供旅游攻略和管理员后台,支持B/S架构,使用Java语言和MySQL数据库,提高了系统的扩展性和维护性。 适合人群:具有一定编程基础的技术人员,特别是熟悉Spring Boot和Vue框架的研发人员。 使用场景及目标:适用于旅游行业,为企业提供一个高效的旅游推荐平台,帮助用户快速找到合适的旅游信息和推荐路线,提升用户旅游体验。系统的智能化设计能够满足用户多样化的需求,提高旅游企业的客户满意度和市场竞争力。 其他说明:系统采用现代化的前后端分离架构,具备良好的可扩展性和维护性,适合在旅游行业中推广应用。开发过程中需要注意系统的安全性、稳定性和用户体验。