`
wupuyuan
  • 浏览: 75849 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

JVM学习笔记之方法调用

阅读更多
最近有空,继续写写jvm的学习笔记。这次写写java中的方法调用过程。
 
    程序在有限的资源下运行当然是越快越好,这就离不开优化。一般来说都是业务逻辑优化(这也是最有效的),说到程序的运行的优化就不得不牵扯到JVM底层的字节码了。查看字节码的方法是javap -c **.class,这里建议  javap -c **.class > **.txt  来保存成文本文件方便用工具查看。
    从class生成的字节码来看,JAVA的方法调用分为4种: invokestatic、invokevirual、invokespecial、invokeinterface 。
 
    为了说明他们的区别,还得说下JVM中类的存贮和方法的早/迟绑定。
    1. Class的类方法的存放地方和属性:
    JVM有一个所有线程间共享的“方法区”,用来存贮每个类结构的常数池、域、方法数据、方法和构造函数。包括类和实例初始化与接口类型初始化中用到的特殊方法。所以每当有线程调用某个类的方法时,都要从方法区调用。java类的方法有很多修饰,比如static、final、private等,这个决定了jvm在底层调用方法上的不同。

    2.方法的早/迟绑定
    简单来说,分辨一个方法是早绑定还是迟绑定可以通过是根据引用调用方法还是通过对象来调用方法。
    当一个方法是static时,在任何地方都可以直接调用,比如Math.abs(4),这个时候就是早绑定,因为这里不需要new,当然没对象了。早绑定不仅仅限于static,当调用private方法时,也是早绑定,因为private只能被自身类方法调用。比如:
Java代码
class A{  
  private void methodA(){}  
}  
        
class B extends A{  
  private void methodB(){}  
}  
  
classA a = new classB();  


    这里是无法这么用a.methodA()和a.methodB(); (原因显而易见,这里就不说了)
    我觉得这样理解private是静态绑定应该好点。
 
    有了以上的说明,可以说清楚方法的具体区别了。
    invokestatic:用于static修饰的方法。任何时候调用只需要所属的CLASS名,无需new,JVM可以直接映射到方法区,是执行速度最快的。如果static方法有参数,则invokestatic指令前还会有个指令,作用是把参数从栈弹出给invokestatic指令。(详细说明这里需要再详细解释下方法运行机制,这里以后再说,这里特别声明是为了和invokevirtual等方法做个区别)
    invokevirtual:用于public和protected修饰的且没有static修饰的方法,在invokevirtual之前,总可以见到astore和aload的指令, 是因为在调用invokevirtual时,会从栈里弹出两个参数,是objectref和我们自定义的参数列表。objectref就是this,因为非static方法不是直接从方法区用的,所以得匹配所属类,是默认的隐式参数,无法从代码层指定objectref。参数列表就是我们自定义的传入参数了。invokevirtual是类的方法调用最慢的指令(因为迟绑定需要多重校验),但是却是运用最多的,java面向对象的多态性离不开它。
    invokespecial:用于3种情况,前2种类默认的方法<init>()和super修饰的方法,它们可以为隐式,<init>()是默认的无参构造函数,super()是默认的调用父类构造函数的函数。当然我们也可以在代码层自定义些参数。invokespecial可以默认从构造函数里递归调用super(),而invokevirtual不行(动态绑定是只运行当前类中的方法)之前说过invokespecial是静态绑定的,如果换用动态绑定是会出错的(例如构造函数的例子),第三种是非static修饰的private方法,原因之前也说了。invokespecial的运行速度比较特殊,在super和init()时,我们可以不用关心(关心也无用,改不了),对于非static的private方法,速度是快于invokevirtual的。
    invokeinterface:用于接口调用的情况,速度是最慢的,因为接口不知道类的具体信息,所以每次运行前得遍历整个类(校验+匹配),而invokevirtual是直接关联类的,方法偏移量是固定的。
 
    这里再补充说明个问题,我看别的帖子说,有final声明的方法也是先绑定的,这里我不清楚,这里只说说我的想法
    首先final是用于不可修改,不可继承的用途,而不是改变使用或者说调用的方法。
    其次,《深入java虚拟机》中也只说了invokestatic和invokespecial是先绑定、invokeinterface和invokevirual没有说明,而我实践javap的时候,所有方法没有因为加了final而改变字节码的方法(不像static),有兴趣可以试试。
 
    最后总结说下大致的代码优化规则。
    首先,4种运行速度为:invokestatic > invokespecial > invokevirual > invokeinterface。
    所以常用的方法是,
    1. 根据具体的业务要求,分离出常用的任务写成static方法,加快速度。有人也怀疑static方法会不会占用更多的内存,我认为不会,因为无论是什么样的方法都得占用方法区的空间,调用也是引用调用。再说对于现在上G的内存,我们写的几K的东西也算不上多大开销。
    2. 遵循高内聚,低耦合的模式,一个类只对外提供必要的public个protected方法,大部分的内部逻辑就用private修饰,一来速度快,二来也免得别人调用起来方法太多看的麻烦。
    3. 对于接口来说,不是接口用的越多越好,抽象出来的接口应该越精简越好,我的亲身体会是接口多了很麻烦,毕竟越灵活的东西越难理解。
 
    我对于方法调用的理解就到这么多,欢迎拍砖。
分享到:
评论
3 楼 jht5945 2012-08-02  
wupuyuan 写道
chenjingbo 写道
invokevirtual 指令与动态分派没有直接的联系.但是invokespecial调用的目标必然是可以静态绑定的(静态 绑定就是你说的早绑定)

具体可以看下我的博客.
http://chenjingbo.iteye.com/blog/1145415

另外你说的四个指令执行速度,我记得好像是没有快慢的关系的.因为我记得好像听撒迦说过
invokeinterface指令执行其实很快.

其他整理的不错哦.

按照早期的虚拟机来说,速度有快慢,比如invokestatic最快是因为没有this这个默认参数,所以不需要根据这个参数做判断,比如类属性等,而其余3个都是需要的,不过现在的虚拟机中加入了大量的内联支持,所以速度上来说都在一个数量级,所以一般写程序不纠结这个,我这么写其实主要是为了规范写代码的习惯,方便理解。
这个是我以前的心得,共勉。


invokeinterface执行速度快还有CHA的原因吧
2 楼 wupuyuan 2011-11-15  
chenjingbo 写道
invokevirtual 指令与动态分派没有直接的联系.但是invokespecial调用的目标必然是可以静态绑定的(静态 绑定就是你说的早绑定)

具体可以看下我的博客.
http://chenjingbo.iteye.com/blog/1145415

另外你说的四个指令执行速度,我记得好像是没有快慢的关系的.因为我记得好像听撒迦说过
invokeinterface指令执行其实很快.

其他整理的不错哦.

按照早期的虚拟机来说,速度有快慢,比如invokestatic最快是因为没有this这个默认参数,所以不需要根据这个参数做判断,比如类属性等,而其余3个都是需要的,不过现在的虚拟机中加入了大量的内联支持,所以速度上来说都在一个数量级,所以一般写程序不纠结这个,我这么写其实主要是为了规范写代码的习惯,方便理解。
这个是我以前的心得,共勉。
1 楼 chenjingbo 2011-11-14  
invokevirtual 指令与动态分派没有直接的联系.但是invokespecial调用的目标必然是可以静态绑定的(静态 绑定就是你说的早绑定)

具体可以看下我的博客.
http://chenjingbo.iteye.com/blog/1145415

另外你说的四个指令执行速度,我记得好像是没有快慢的关系的.因为我记得好像听撒迦说过
invokeinterface指令执行其实很快.

其他整理的不错哦.

相关推荐

    java7rt.jar源码-Java_JVM:这是我的JavaJVM学习笔记

    Runtime或System类调用exit()方法或Runtime调用half()方法 JVM的框架: 执行引擎: (字节)解释器 + JIT(java即时编译器) 前者是用 PC计数器 来依次编译每一行代码解释为本地机器指令; 后者是通过 寻找热点代码 进行...

    Java JDK 7学习笔记(国内第一本Java 7,前期版本累计销量5万册)

     《Java JDK 7学习笔记》将IDE操作纳为教学内容之一,使读者能与实践结合,提供的视频教学能更清楚地帮助读者掌握操作步骤。 内容简介 书籍 计算机书籍  《java jdk 7学习笔记》是作者多年来教学实践经验的总结...

    net学习笔记及其他代码应用

    要请求垃圾收集,可以调用下面的方法之一: System.gc() Runtime.getRuntime().gc() 37.String s = new String(\"xyz\");创建了几个String Object? 答:两个对象,一个是“xyx”,一个是指向“xyx”的引用对象s。...

    Java学习笔记

    在不同的操作系统之上可以不用做任何代码的修 改 直接使用 a) 字节码文件:字节码文件不包括任何内存布 局信息 与操作系统和硬件毫无关系 (Java 的内存分布是在运行的时候才动态分配的) b) JVM:真正解释字节码文件...

    scala.rar学习笔记和心得

    Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。...Scala 源代码被编译成Java字节码,所以它可以运行于JVM之上,并可以调用现有的Java类库。

    Java并发编程(学习笔记).xmind

    远程方法调用(RMI) 正确协同多个对象中的共享状态 正确协同远程对象本身状态的访问 Swing和AWT 事件处理器与访问共享状态的其他代码都要采取线程安全的方式实现 框架通过在框架线程中调用...

    java8rt.jar源码-JVM:学习JVM

    JVM的重要性不言而喻,这个是学习JVM是看视频和读《深入理解JVM》时做的一些笔记,用于复习参考。 读书笔记 第2章:java内存模型和内存溢出异常 1.运行时数据区域 1.程序计数器:线程私有 2.java虚拟机栈:线程私有...

    springboot学习思维笔记.xmind

    springboot学习笔记 spring基础 Spring概述 Spring的简史 xml配置 注解配置 java配置 Spring概述 Spring的模块 核心容器CoreContainer Spring-Core Spring-Beans ...

    java8源码-JavaSE-Code:JavaSE的代码练习与学习笔记总结

    interrupted是Thread类的静态方法,里面调用了isTnterrupted方法[currentThread().isInterrupted()],测试当前线程是否已经中断,线程的中断状态由该方法清除 isInterrupted是Thread类的实例方法,不清除中断标志 yield...

    清华妹子的Java仓库(进阶学习路线)

    本仓库记录了我的Java学习进阶之路,涵盖了Java基础、JDK源码、JVM中的重要知识,附有代码和博客讲解,旨在提供一个Java在线共享学习平台,帮助更多的Java学习入门者进阶。 Java学习 本仓库记录了我的Java学习进阶...

    积分java源码-java-11:Java11OCP学习笔记

    积分java源码Java 11 Java SE ...表达式由变量、运算符和方法调用组成。 表达式计算为单个值。 表达式是计算值的东西,而语句是做某事的一行代码。 某些表达式可以通过以分号结尾的方式组成语句,例

    酒店管理客房系统Java源码-GOF23:Java实现23种设计模式学习笔记

    工厂方法模式:用来生产同一等级结构中的固定产品(支持增加任意产品,不用修改源代码)将工厂类调整为工厂接口,需要什么类型的工厂就使用该类实现该工厂,创建相应的产品。 :用来生产不同产品族的全部产品(对于...

    jive.chm

    系统设计 1 jive设计思路 2 jive的工作内幕 3 Jive源代码研究 4 Jive中的设计模式 5 jive学习笔记 &lt;br&gt; 设计模式 1 大道至简-Java之23种模式一点就通 2 设计模式...

    关于Scala那些事儿

    这是一份总结的学习笔记 路漫漫其修远兮,吾将上下而求索 可阅读可评论可分享可转载,希望向优秀的人学习 前言 Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种...

    Jive资料集

    系统设计 1 jive设计思路 2 jive的工作内幕 3 Jive源代码研究 4 Jive中的设计模式 5 jive学习笔记 &lt;br&gt; &lt;br&gt; 数据库设计 1 Jive Forums数据库说明(英文) 2 Jive KB...

    jedis使用指南

    具体事务和监听请参考文章:redis学习笔记之事务 暂时找到三种实现方式: 1. 通过jedis.setnx(key,value)实现 import java.util.Random; import org.apache.commons.pool.impl.GenericObjectPool.Config; import ...

    java版斗地主源码-MyJava:记录我自己Java学习的一些笔记,才疏学浅还望多多指教

    因为类调用时需要实例化,开销比较大,比较消耗资源,所以当性能是最重要的考量因素的时候,比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发。但是,面向过程没有面向对象易维护、易复用、易扩展。 面向...

    Eclipse开发分布式商城系统+完整视频代码及文档

    │ 淘淘商城第一天笔记.docx │ ├─02.第二天 │ 07.商品类目选择完成.avi │ 01.课程计划.avi │ 02.展示首页.avi │ 03.分页插件01.avi │ 04.分页插件的使用方法.avi │ 05.商品列表展示.avi │ 06.商品类目...

    程序员面试刷题的书哪个好-thinkingInJava:学习《thinkinginjava》一书

    程序员面试刷题的书哪个好 ...通常来说,我们用new创建对象后,才能调用这个对象的方法。否则,并未获得任何对象。 通常,我们需要创建一个对象,来访问这个对象的数据或方法,因为非static域和方法必须和

    java笔试题算法-javase:javase的笔记

    向下,生动清晰阐述JVM原理,内存管理,垃圾回收算法,系统调用,多线程及各种锁实现源码分析,BIO/NIO/AIO到Netty源码原理,全程项目贯穿,推动理论实践,上课等于上班,经验超过传统教学后工作一年经验,夯实的...

Global site tag (gtag.js) - Google Analytics