jvmjvm性能调优

java基础知识,字节码执行引擎

2020-02-24  本文已影响0人  javap

知识要点:

函数解析

静态分派

动态分派

字节码

函数解析

虚拟机方法字节码

在Java语言中符合“编译期可知,运行期不可变”。这个要求的方法,主要包括静态方法和私有方法两大类,前者与类型直接关联,后者在外部不可被访问,这两种方法各自的特点决定了它们都不可能通过继承或别的方式重写其他版本,因此它们都适合在类加载阶段进行解析。
与之相对应的是,在Java虚拟机里面提供了5条方法调用字节码指令,分别如下:

静态类型和实际类型

Human man=new Man();

上面代码中的“Human”称为变量的静态类型(Static Type),或者叫做的外观类型(Apparent Type),后面的“Man”则称为变量的实际类型(Actual Type)

虚方法

虚方法表

虚方法表(Vritual Method Table,也称为vtable,与此对应的,在invokeinterface执行时也会用到接口方法表itable)使用虚方法表索引来代替元数据查找以提高性能。虚方法表中存放着各个方法的实际入口地址。虚方法表一般是在类加载的阶段进行初始化。


静态分派

所有依赖静态类型来定位方法执行版本的分派动作称为静态分派。静态分派的典型应用是方法重载。静态分派发生在编译阶段,因此确定静态分派的动作实际上不是由虚拟机来执行的。

public class StaticDispatch {
   static abstract class Human {
   }

   static class Man extends Human {
   }

   static class Woman extends Human {
   }

   // overload(多分派)
   public void sayHello(Human guy) {
      System.out.println("hello,guy!");
   }

   public void sayHello(Man guy) {
      System.out.println("hello,gentleman!");
   }

   public void sayHello(Woman guy) {
      System.out.println("hello,lady!");
   }


   public static void main(String[] args) {
      int i = 0;
      int m = 1;
      Human man = new Man();
      Human woman = new Woman();
      StaticDispatch sr = new StaticDispatch(); // new invokespecial
      // 下面两句函数调用是:运行时决定,还是编译时决定?
      // invokevirtual  静态分派 编译器决定
      sr.sayHello(man);     // invokevirtual
      sr.sayHello(woman);   // invokevirtual
   }
}

编译器在重载时是通过参数的静态类型而不是实际类型作为判定依据的。并且静态类型是编译期可知的,因此,在编译阶段,Javac编译器会根据参数的静态类型决定使用哪个重载版本。

动态分派

不是根据静态类型来确定,而是在运行时根据实际类型来决定函数的版本。

public class DynamicDispatch {
   static class Human {
      protected void sayHello(){
         System.out.println("Human");
      };
   }

   static class Man extends Human {
      @Override
      // 单分派
      protected void sayHello() {
         System.out.println("man say hello");
      }
   }

   static class Woman extends Human {
      @Override
      protected void sayHello() {
         System.out.println("woman say hello");
      }
   }

   public static void main(String[] args) {
      // 动态分派。不是根据静态类型来确定,而是在运行时根据实际类型来决定函数的版本。
      // 静态类型 Human man
      // 实际类型 new Man()
      Human man = new Man();       // invokespecial
      Human woman = new Woman();   // invokespecial
      man.sayHello();    // invokevirtual
      woman.sayHello();  // invokevirtual
      man = new Woman(); // new Woman
      man.sayHello();    // invokevirtual #n
   }
}

Java语言是一门静态多分派、 动态单分派的语言。

字节码

Java虚拟机的字节码指令由两部分组成

字节码指令分类

上一篇 下一篇

猜你喜欢

热点阅读