Java为何需要平衡方法调用与内联

 更新时间:2021年01月29日 14:40:54   作者:干货满满张哈希  
这篇文章主要介绍了Java为何需要平衡方法调用与内联,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下

在 Java 中,方法调用一般通过 Virtual Call 还有 Classic Call。

Classic Call 就是直接指向方法的地址,需要一次寻址到方法的地址,比直接执行代码慢。

Virtual Call 需要通过 VMT(Virtual Method Table)。这个VMT存储的是该class对象中所有的Virtual Method,程序运行的时候首先加载实例对象,然后通过实例对象找到VMT,通过VMT再找到对应的方法地址,再执行代码。所以比 Classic Call 更慢。

Java 中除了 static 方法,private 方法以及构造器是 Classic Call 之外,基本都是 Virtual Call。

为了优化,JVM 运行时,JVM使用混合模式来从字节码转换成机器可以运行的机器码,混合模式包括解释器和JIT:

解释器工作机制:

在编译时,主要是将java源代码文件编译为java统一的字节码,但是编译成的字节码并不能直接运行,而是通过JVM读取运行。JVM中的解释器就是将.class文件一行一行翻译之后再运行,翻译就是转换成当前机器可以运行的机器码,它不会一次性把整个文件都翻译过来,而是翻译一句,执行一句,再翻译,再执行,所以解释器的程序运行起来会比较慢,每次都要解释之后再执行。所以,有些时候,我们想是否可以把解释之后的内容缓存起来,这样不就可以直接运行了?但是,如果每段代码都要缓存起来,例如仅仅执行一次的代码也缓存起来,这样太浪费内存了。所以,引入一个新的运行时编译器,JIT来解决这些问题,加速热点代码的执行。

JIT运行时编译器工作机制: 

JIT针对热点代码,进行编译与深度优化,优化后的机器码会被缓存起来,存入CodeCache(代码高速缓存)中。对于非热点代码,例如只运行一次的代码(类构造器等等),直接解释执行,更加快速。JIT不仅花更多时间去编译优化,而且还多耗费了很多内存。字节码转换为可执行的机器码,大小会大很多很多倍。这也是为啥,解释器每次都要翻译并且执行,JIT只针对热点代码进行编译优化的原因。JIT编译器执行的一些常见优化操作包括数据分析,从堆栈操作到寄存器操作的转换,通过寄存器分配减少内存访问,消除常见子表达式等。JIT编译器进行的优化程度越高,在执行阶段花费的时间越多。因此,JIT编译器无法承担所有静态编译器所做的优化,这不仅是因为增加了执行时间的开销,而且还因为它只对程序进行了限制。这也就解释了为什么有些JVM会选择不总是做JIT编译,而是选择用解释器+JIT编译器的混合执行引擎。

JIT其中一项很重要的优化就是内联: 内联是将较小方法的树合并或“内联”到其调用者的树中的过程。这样可以加速频繁执行的方法调用。不同分层优化阶段,使用的算法不同。主要包括:

  • Trivial方法内联
  • 调用图内联
  • 尾部递归消除
  • 虚拟调用优化

这样省略了 calling method。但是,如果将所有方法都内联的话,编译出来的机器码会很大很大,内存占用会急剧增高,效率低下。所以,需要 JIT 把握好这个优化的度

总结起来就是:JIT 是即时优化并编译代码,优化代码包括内联,编译后的代码保存在内存中,也就是代码高速缓存,编译后的代码是很大的,所以不能所有代码都编译,需要是热点代码。并且,内联也会将这个方法变得更大。代码高速缓存也是需要清理的,代码高速缓存占用过高,也会增加清理概率,因为你可能几个方法都是高频执行,但是编译之后占用过大导致超过代码高速缓存限制,那么会发生代码高速缓存清理,就是代码缓存中的编译代码一直在换。清理代码高速缓存,会让所有线程进入 Safepoint,然后才能清理,也就是 stop the world。内联过多,方法变大,这种清理频率也会变大。

以上就是Java为何需要平衡方法调用与内联的详细内容,更多关于Java 平衡方法调用与内联的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:

相关文章

  • JVM中堆内存和栈内存的区别

    JVM中堆内存和栈内存的区别

    本文主要介绍了JVM中堆内存和栈内存的区别,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • Spring Boot项目如何优雅实现Excel导入与导出功能

    Spring Boot项目如何优雅实现Excel导入与导出功能

    在我们平时工作中经常会遇到要操作Excel的功能,比如导出个用户信息或者订单信息的Excel报表,下面这篇文章主要给大家介绍了关于Spring Boot项目中如何优雅实现Excel导入与导出功能的相关资料,需要的朋友可以参考下
    2022-06-06
  • springmvc实现简单的拦截器

    springmvc实现简单的拦截器

    这篇文章主要为大家详细介绍了springmvc实现简单拦截器的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-05-05
  • 用Java生成二维码并附带文字信息

    用Java生成二维码并附带文字信息

    这篇文章主要介绍了用Java生成二维码并附带文字信息,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04
  • Java中如何比较两个数组中元素是否相同

    Java中如何比较两个数组中元素是否相同

    比较两个数组中的元素是否相同,在项目中经常会使用到,下面与大家分享个最简单的方法
    2014-06-06
  • springboot整合RabbitMQ发送短信的实现

    springboot整合RabbitMQ发送短信的实现

    本文会和SpringBoot做整合,实现RabbitMQ发送短信,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • Java Lambda List转Map代码实例

    Java Lambda List转Map代码实例

    这篇文章主要介绍了Java Lambda List转Map代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • SpringBoot中Zookeeper分布式锁的原理和用法详解

    SpringBoot中Zookeeper分布式锁的原理和用法详解

    Zookeeper是一个分布式协调服务,它提供了高可用、高性能、可扩展的分布式锁机制,SpringBoot是一个基于Spring框架的开发框架,它提供了对Zookeeper分布式锁的集成支持,本文将介绍SpringBoot中的 Zookeeper分布式锁的原理和使用方法,需要的朋友可以参考下
    2023-07-07
  • java判断某个点是否在所画多边形/圆形内

    java判断某个点是否在所画多边形/圆形内

    这篇文章主要为大家详细介绍了java判断某个点是否在所画多边形或圆形内的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-05-05
  • MyBatis实现多表联合查询resultType的返回值

    MyBatis实现多表联合查询resultType的返回值

    这篇文章主要介绍了MyBatis多表联合查询resultType的返回值,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03

最新评论