JVM是如何实现方法调用的

JVM是如何识别到低该调用哪个方法的:

JVM是根据 类名+方法名+方法描述符(形参+返回类型) 来识别到底该调用哪一个方法的。

其中,重载方法的匹配优先级规则如下(Java中的重载不会根据返回类型来区分):

  1. 优先调用非自动装拆箱的
  2. 在1不行的情况下,允许自动装箱
  3. 在2也不行的情况下,允许可变长参数

 

按照绑定类型分,可以将方法分为静态绑定和动态绑定两种:

其中,绑定是指将一个方法与其所在的类/对象关联起来的方法。

静态绑定是指程序运行前就已经知道方法属于哪个类,在编译的时候就可以连接到类中定位到这个方法。在Java中,finalprivatestatic修饰的方法以及构造方法都是属于这种类型。

动态绑定是指在程序运行过程中,更加具体的对象才能具体确定是哪个方法。(多态)

 

我们再从JVM层面分析下,JVM里面是通过哪里指令来实现方法的调用的:

  1. invokestatic:调用静态方法
  2. invokeinterface:调用接口方法(多态)
  3. invokespecial:调用非静态私有方法、构造方法(包括super)
  4. invokevirtual:调用非静态非私有方法(多态)
  5. invokedynamic:动态调用(Java7引入的,第一次用却是在Java8中,用在了Lambda表达式和默认方法中,它允许调用任意类中的同名方法,注意是任意类,重载重写不同)(动态 ≠ 多态)

 

那么这些指令又是怎么来调用方法的呢?(invokedynamic和这些有点不一样,稍后单独解释下)

在编译的过程中,JVM并不知道目标方法的具体内存地址,此时编译器会用”符号引用”来表示该方法(加载阶段)。当JVM进行到“解析”阶段的时候,这些引用会被替换为直接引用,这个时候就知道需要去哪里调用到方法了!

对于静态绑定的方法,直接引用就是直接指向方法的指针,而对于动态绑定的方法,直接引用其实指向方法表中的一个索引。

方法表是一个数组,每个数组元素指向一个当前类及其父类中非private的实例方法,样子如下所示:

由于动态绑定相比于静态绑定,在寻找方法时要出多好一个内存解析的动作,例如获取调用者类型,获取方法表,获取方法表的索引值等等,还是有点开销的,虽然这些开销是必须的。所以JVM中引入了一些优化的技术: 内存缓联+方法内联。

 

动态绑定调用优化技术:

内存缓联:

说白了就是缓存,缓存的调用者的类型已经改类型所对应的目标方法,如果以后执行时,直接拿寻找缓存中对应的方法,不然就要去方法表中查询了(类似与操作系统的pagecache)。(非动态绑定的算法是不需要缓存的)

方法内联:

任何一个方法调用,除非它被内联,否则都会有固定开销。这些开销主要是保存程序在改方法中的执行位置,以及新建、压入和弹出新方法所使用中的栈帧。对于一些非常简单的方法例如getter/setter,这部分开销耗费的时间可能超过方法本身。

方法内联就是将调用函数的表达式直接用函数的函数体来直接替换,这样就减少了寻址开销,虽然可能会增加目标程序的代码量(增加空间开销),这是一个很重要的优化方法,由JVM来实现。

 

独特的Invokedynamic:

前面四种指令是吧符号引用替换为直接引用,直接指到内存中的地址,也就是说他们需要指导方法所在类名,方法名以及方法描述符。但是像Lambda表达式这种,尤其是scala,只要方法描述符(又叫方法签名)对上了,可以使用引用到其他类中的方法(任意Function类中的apply)。

也就是说需要有这么一个指令,可以允许程序将调用点连接到任意符合条件的方法上,这就需要用到反射机制了,但是反射调用有反复权限检查的开销,所以JVM在底层引入了轻量级的方法句柄(MethodHandle)的概念,并由JVM对它做一些优化(如方法内联)。

可以这么理解Reflection API设计失误诶Java语言服务的,而MethodHandle则为所有运行在JVM之上的语言服务。

 

参考:

https://www.cnblogs.com/ygj0930/p/6554103.html(Java中的静态与动态绑定)

https://blog.csdn.net/ke_weiquan/article/details/51946174(JVM内联函数)

https://zhuanlan.zhihu.com/p/26389041(invokedynamic解释)

https://www.jianshu.com/p/3421f23e0fde(反射与方法句柄的异同)

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值