JVM处理方法调用与返回(译)

方法调用

java程序语言提供了两种基本方法:实例方法和类(静态)方法.其不同点是:

  1. 实例方法在调用前需要一个对象实例,而类方法不需要.
  2. 实例方法使用动态绑定,而类方法使用静态绑定.

JVM用invokevirtualinvokestatic两种不同的指令来分别处理实例方法和类方法的调用.

动态链接

符号引用 是一簇唯一标识一个方法,包括类名,方法名,和方法描述(方法返回值,参数类型等)等信息的存放在常量池中的标识.当在运行时,遇到方法调用的指令时,就会解决符号引用.

为了解决符号引用,JVM定位到被符号引用的标识,并将其替换成直接引用.直接引用,比如一个指针或一个偏移量,能够使虚拟机调用方法更快(没有使用过).

验证

在将符号引用转成直接引用时,JVM会附加执行一些验证检查操作.这些检查确保java语言规则被遵守并且调用指令能被安全执行.比如,虚拟机首先确保符号引用的方法存在.如果存在,虚拟机检查确保当前类能合法进入到要调用的方法.比如,如果方法是private,它必须是当前类的成员.如果有一个检查失败,JVM将抛出异常.

对象引用和参数问题

在上面准备好了直接引用后,JVM将要准备参数,实例方法需要有对象引用.这些参数必须在调用指令之前必须通过字节码指令push到调用方法(发起方)的操作数栈中.

Pushing and poping 栈帧

调用一个方法时,JVM将为被调用方法创建一个新的栈帧.栈帧包括方法的本地变量表、操作数栈和该虚拟机特殊实现需要的其他信息.本地变量表和操作数栈的大小在编译时就已经计算好了.

当方法调用时将在栈中增加一个新的栈帧就叫做Pushing一个栈帧.当方法返回时移除一个栈帧叫做poping一个栈帧.

调用java方法

当调用一个java方法时,JVM将push一个新的栈帧到当前的java栈中.

针对一个实例方法,VM 将pops调用方法栈帧中的对象引用和操作数栈中的参数.JVM创建一个新的栈帧,并且将新的栈帧中本地变量的0(this)替换为对象引用,其他的1、2替换为其他参数.

针对类方法,VM仅仅调用方法栈帧中的操作数栈中的参数,并用他们替换新的栈帧中的本地变量0,1,2....

一旦新的栈帧中的本地变量表替换完成,VM将新的栈帧作为当前栈帧并且设置程序计数器指向新方法的第一条指令.

The JVM specification does not require a particular implementation for the Java stack. Frames could be allocated individually from a heap, or they could be taken from contiguous memory, or both. If two frames are contiguous, however, the virtual machine can just overlap them such that the top of the operand stack of one frame forms the bottom of the local variables of the next. In this scheme, the virtual machine need not copy objectref and args from one frame to another, because the two frames overlap. The operand stack word containing objectref in the calling method's frame would be the same memory location as local variable 0 of the new frame

调用本地方法

如果调用的方法是本地方法,JVM以一种依赖实现的方法来调用。VM不会为本地方法向java栈push一个新的栈帧,At the point at which the thread enters the native method, it leaves the Java stack behind. When the native method returns, the Java stack once again will be used.

其他方法调用形式

尽管实例方法一般通过invokevirtual来调用,然而invokespecialinvokeinterface这两个操作码被用来调用某种情形的特殊方法.

invokespecial用于基于引用类型的实例化方法.用于三种情形:

  1. 调用实力初始化(<init>)方法
  2. 调用私有方法
  3. 调用使用super关键字的方法

invokeinterface用来调用一个接口引用的实例方法.

invokespecialinvokevirtual不同点:

invokespecial选择的方法是基于引用类型而不是对象的类类型.或者说,是静态绑定而不是动态绑定。

invokespecial与私有方法

class Superclass {
    private void interestingMethod() {
        System.out.println("Superclass's interesting method.");
    }
    void exampleMethod() {
        interestingMethod();
    }
}
class Subclass extends Superclass {
    void interestingMethod() {
        System.out.println("Subclass's interesting method.");
    }
    public static void main(String args[]) {
        Subclass me = new Subclass();
        me.exampleMethod();
    }
}

以上将打印:

Superclass's interesting method.

由于invokespecial,VM将选择基于引用类型的方法,所以如此打印.

方法调用事例

interface inYourFace {
    void interfaceMethod ();
}
class itsABirdItsAPlaneItsSuperClass implements inYourFace {
    itsABirdItsAPlaneItsSuperClass(int i) {
        super();                    // invokespecial (of an <init>)
    }
    static void classMethod() {
    }
    void instanceMethod() {
    }
    final void finalInstanceMethod() {
    }
    public void interfaceMethod() {
    }
}
class subClass extends itsABirdItsAPlaneItsSuperClass {
    subClass() {
        this(0);                    // invokespecial (of an <init>)
    }
    subClass(int i) {
        super(i);                   // invokespecial (of an <init>)
    }
    private void privateMethod() {
    }
    void instanceMethod() {
    }
    final void anotherFinalInstanceMethod() {
    }
    void exampleInstanceMethod() {
        instanceMethod();             // invokevirtual
        super.instanceMethod();       // invokespecial
        privateMethod();              // invokespecial
        finalInstanceMethod();        // invokevirtual
        anotherFinalInstanceMethod(); // invokevirtual
        interfaceMethod();            // invokevirtual
        classMethod();                // invokestatic
    }
}
class unrelatedClass {
    public static void main(String args[]) {
        subClass sc = new subClass(); // invokespecial (of an <init>)
        subClass.classMethod();       // invokestatic
        sc.classMethod();             // invokestatic
        sc.instanceMethod();          // invokevirtual
        sc.finalInstanceMethod();     // invokevirtual
        sc.interfaceMethod();         // invokevirtual
        inYourFace iyf = sc;
        iyf.interfaceMethod();        // invokeinterface
    }
  }

方法返回

JVM会使用针对每一种返回类型的操作来返回.返回值将从操作数栈pop并且push到调用方法的方法栈帧中.当前的栈帧pop,被调用方法的栈帧变成当前的.程序计数器将重置为调用这个方法的指令的下一条指令.

操作码描述:

  1. ireturn none pop int, push onto stack of calling method and return

  2. lreturn none pop long, push onto stack of calling method and return

  3. freturn none pop float, push onto stack of calling method and return

  4. dreturn none pop double, push onto stack of calling method and return

  5. areturn none pop object reference, push onto stack of calling method and return

  6. return none return void

    The ireturn instruction is used for methods that return int, char, byte, or short.

结论

  1. 实例方法是动态绑定的,除了<init>、private和super关键字调用的方法,这三种特殊情况,实例方法是静态绑定的.
  2. 类方法是静态绑定的.
  3. 与接口引用相关的实例方法可能比同样的对象关联的方法慢.

参考链接

how the java virtual machine handles method invocation and return

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容