动态编译和静态编译_动态编译和性能评估

本文探讨了Java动态编译的历史,包括即时编译、热点动态编译和堆叠更换等概念。重点讲述了动态编译如何影响性能测量,尤其是微基准测试中的陷阱,如死代码消除、暖身、动态反优化等问题,强调了理解和避免这些因素对准确评估Java代码性能的重要性。
摘要由CSDN通过智能技术生成

我本月开始写一篇文章,剖析写得不好的微基准。 毕竟,我们程序员痴迷于性能,并且我们每个人都希望了解我们编写,使用或批评的代码的性能特征。 当我偶尔写关于性能的文章时,我经常收到人们的电子邮件,说:“我写的这个程序表明,与上一篇文章相反,动态雾化比静态雾化更快!” 伴随此类电子邮件的许多所谓的“基准”程序或它们的运行方式,显示出对JVM如何实际执行Java字节码的认识非常缺乏。 因此,在写我打算写的文章之前(将在以后的专栏中介绍),让我们看一下JVM的内幕。 了解动态编译和优化是了解如何从坏的基准中分辨出好的微基准(关键是很少的基准)的关键。

动态编译-简要历史

Java应用程序的编译过程与C或C ++之类的静态编译语言不同。 静态编译器将源代码直接转换为可以在目标平台上直接执行的机器代码,并且不同的硬件平台需要不同的编译器。 Java编译器将Java源代码转换为可移植的JVM字节码,这是JVM的“虚拟机指令”。 与静态编译器不同,javac很少进行优化-由编译器以静态编译语言完成的优化是在程序执行时由运行时执行的。

第一代JVM被完全解释。 JVM解释了字节码,而不是将其编译为机器代码并直接执行机器代码。 当然,这种方法不能提供最佳的性能,因为系统执行解释器所花的时间比应该运行的程序要多。

即时编译

对于概念验证的实现来说,解释是可以的,但是早期的JVM由于速度慢而很快受到了不好的好评。 下一代JVM使用即时(JIT)编译器来加快执行速度。 严格定义,基于JIT的虚拟机会在执行之前将所有字节码转换为机器代码,但是这样做是偷懒的:JIT仅在知道要执行的代码路径时才编译代码路径(因此,名称,名称, 即时编译)。 这种方法使程序可以更快地启动,因为在开始执行之前不需要冗长的编译阶段。

JIT方法似乎很有希望,但是它有一些缺点。 JIT编译消除了解释的开销(以一些额外的启动成本为代价),但是由于一些原因,代码优化的水平中等。 为了避免Java应用程序的大量启动损失,JIT编译器必须快速运行,这意味着它不能花太多时间进行优化。 早期的JIT编译器在进行内联假设时比较保守,因为他们不知道以后会加载哪些类。

从技术上讲,基于JIT的虚拟机会在执行每个字节码之前先对其进行编译,但术语JIT通常用于指代将字节码动态编译为机器代码的方法,甚至也包括那些能够解释字节码的代码。

热点动态编译

HotSpot执行过程结合了解释,概要分析和动态编译。 HotSpot不会在执行之前将所有字节码转换为机器代码,而是首先以解释器的身份运行,并且仅编译“热”代码-最常执行的代码。 在执行时,它会收集概要分析数据,用于确定执行频率最高的代码段,足以值得编译。 仅编译频繁执行的代码具有几个性能优势:不会浪费时间去编译很少执行的代码,因此,编译器可以花更多的时间在热代码路径的优化上,因为它知道这样的时间将被很好地利用。 此外,通过推迟编译,编译器可以访问分析数据,该数据可用于改进优化决策,例如是否内联特定的方法调用。

为了使事情变得更复杂,HotSpot带有两个编译器:客户端编译器和服务器编译器。 默认是使用客户端编译器; 您可以在启动JVM时通过指定-server开关来选择服务器编译器。 服务器编译器已经过优化,可以最大程度地提高峰值运行速度,并且适用于长时间运行的服务器应用程序。 已对客户端编译器进行了优化,以减少应用程序启动时间和内存占用量,与服务器编译器相比,采用的复杂优化更少,因此,所需的编译时间也更少。

HotSpot服务器编译器可以执行各种令人印象深刻的优化。 它可以执行静态编译器中的许多标准优化,例如代码提升,通用子表达式消除,循环展开,范围检查消除,死代码消除和数据流分析,以及各种其他非优化方法。在静态编译语言中实用,例如积极地内联虚拟方法调用。

连续重新编译

HotSpot方法的另一个有趣的方面是,编译不是一个全有或全无的主张。 在解释了一定数量的代码路径后,将其编译为机器代码。 但是JVM会继续进行性能分析,并且如果JVM确定代码路径特别热,或者将来的性能分析数据表明有进一步优化的机会,则可以稍后以更高的优化级别再次重新编译代码。 JVM可以在单个应用程序执行中多次重新编译相同的字节码。 要了解编译器在做什么,请尝试使用-XX:+PrintCompilation标志调用JVM,这会导致编译器(客户端或服务器)在每次运行时打印一条短消息。

堆叠更换

HotSpot的初始版本一次执行一种编译方法。 如果某个方法累积执行的循环迭代次数超过一定次数(HotSpot的第一个版本为10,000),则该方法被认为是热方法,该迭代是通过将计数器与每种方法相关联并在每次执行向后转移时递增该计数器来确定的。 但是,在编译方法之后,直到方法退出并重新输入后,它才切换到编译版本-编译版本仅用于后续调用。 在某些情况下,结果是从未使用过编译版本,例如ÿ

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
静态测试和动态测试是软件质量保证过程中的两种基本方法,它们在软件开发生命周期中扮演着不同的角色。 1. **静态测试**(Static Testing): 静态测试发生在代码被执行之前,通常是在编译期间或设计阶段进行的。这些测试不涉及实际运行代码,而是通过检查源代码、架构设计文档、需求规格等方式来进行。常见的静态测试包括: - 代码审查:检查代码风格、结构、错误、是否符合编程规范等。 - 代码质量工具分析:使用工具检测潜在的问题,如冗余代码、安全漏洞等。 - 需求规格和设计评审:确保需求和设计符合预期。 2. **动态测试**(Dynamic Testing): 动态测试则是执行时对程序进行的验证,包括单元测试、集成测试、系统测试和验收测试等。这类测试关注的是程序在实际运行环境中的行为: - 单元测试:针对程序模块的功能进行验证,确保每个部分按预期工作。 - 集成测试:多个模块组合起来测试,检查接口和交互是否正确。 - 系统测试:在模拟的或真实的环境中测试整个应用程序,验证功能的完整性和性能。 - 压力测试和负载测试:评估系统的极限情况和响应能力。 - 动态分析:使用工具分析程序运行时的行为,比如内存泄漏检测、性能监控等。 相关问题: 1. 静态测试与动态测试的主要区别是什么? 2. 何时会进行静态测试?何时进行动态测试? 3. 在软件开发过程中,如何平衡静态测试和动态测试的时间分配?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值