java代码是怎么运行的

一、什么是字节码、机器码、本地代码?

1.字节码是指平常所了解的 .class 文件,Java 代码通过 javac 命令编译成字节码

2.机器码和本地代码都是指机器可以直接识别运行的代码,也就是机器指令(机器码是与平台相关的,也就是操作系统相关)

3.字节码是不能直接运行的,需要经过 JVM 解释或编译成机器码才能运行

二、Java 虚拟机具体是怎样运行 Java 字节码的?

1.java 虚拟机将运行时内存区域划分为五个部分,分别为方法区、堆、PC 寄存器、Java 方法栈和本地方法栈。Java 程序编译而成的 class 文件,需要先加载至方法区中,方能在 Java 虚拟机中运行。在运行过程中,每当调用进入一个 Java 方法,Java 虚拟机会在当前线程的 Java 方法栈中生成一个栈帧,用以存放局部变量以及字节码的操作数。这个栈帧的大小是提前计算好的,而且 Java 虚拟机不要求栈帧在内存空间里连续分布。当退出当前执行的方法时,不管是正常返回还是异常返回,Java 虚拟机均会弹出当前线程的当前栈帧,并将之舍弃。

java代码是怎么运行的

三、什么是编译和解释?

在 HotSpot 里面,翻译过程有两种形式:第一种是解释执行,即逐条将字节码翻译成机器码并执行;第二种是即时编译(Just-In-Time compilation,JIT),即将一个方法中包含的所有字节码编译成机器码后再执行。(智能地对热点代码进行优化且重复利用)  二八定律

java代码是怎么运行的

判断一段代码是否是热点代码,是否需要触发即使编译,这样的行为称为热点探测,热点探测并不一定知道方法具体被调用了多少次,目前主要的热点探测判定方式有两种:采样和计数

四、Java虚拟机是如何加载Java类的?

从 class 文件到内存中的类,按先后顺序需要经过加载、链接以及初始化三大步骤。其中,链接过程中同样需要验证;而内存中的类没有经过初始化,同样不能使用

加载是指查找字节流,并且据此创建类的过程。对于数组类来说,是由 Java 虚拟机直接生成的。对于其他的类来说,Java 虚拟机则需要借助类加载器来完成查找字节流的过程。

双亲委派模型:每当一个类加载器接收到加载请求时,它会先将请求转发给父类加载器。在父类加载器没有找到所请求的类的情况下,该类加载器才会尝试去加载。

应用类加载器->扩展类加载器->启动类加载器(注意:类的唯一性是由类加载器实例以及类的全名一同确定的。即便是同一串字节流,经由不同的类加载器加载,也会得到两个不同的类。)

链接,它可分为验证、准备以及解析三个阶段。验证是否满足条件,准备是给被加载类的静态字段分配内存,除了分配内存外还会构造与该类相关联的方法表,在 class 文件被加载至 Java 虚拟机之前,这个类无法知道其他类及其方法、字段所对应的具体地址,甚至不知道自己方法、字段的地址。因此,每当需要引用这些成员时,Java 编译器会生成一个符号引用。在运行阶段,这个符号引用一般都能够无歧义地定位到具体目标上。而解析阶段的目的,正是将这些符号引用解析成为实际引用。如果符号引用指向一个未被加载的类,或者未被加载类的字段或方法,那么解析将触发这个类的加载(但未必触发这个类的链接以及初始化。)

初始化,静态字段被 final 所修饰,并且它的类型是基本类型或字符串时,那么该字段便会被 Java 编译器标记成常量值,其初始化直接由 Java 虚拟机完成。除此之外的直接赋值操作,以及所有静态代码块中的代码,则会被 Java 编译器置于同一方法中,并把它命名为 < clinit >。类加载的最后一步是初始化,便是为标记为常量值的字段赋值,以及执行 < clinit > 方法的过程。Java 虚拟机会通过加锁来确保类的 < clinit > 方法仅被执行一次。

五、类的初始化被触发的几种情况

1.当虚拟机启动时,初始化用户指定的主类;

2.当遇到用以新建目标类实例的 new 指令时,初始化 new 指令的目标类;

3.当遇到调用静态方法的指令时,初始化该静态方法所在的类;

4.当遇到访问静态字段的指令时,初始化该静态字段所在的类;

5.子类的初始化会触发父类的初始化;

6.如果一个接口定义了 default 方法,那么直接实现或者间接实现该接口的类的初始化,会触发该接口的初始化;

7.使用反射 API 对某个类进行反射调用时,初始化这个类;

8.当初次调用 MethodHandle 实例时,初始化该 MethodHandle 指向的方法所在的类。

六、JVM是如何执行方法调用的?

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzfdpf.html