在线.class文件转换.java_Java代码运行的整个过程是怎样运行的?你知道吗?

19d2aa3190a4747fe85ac5b471bc3ce9.png

前几天去面试,面试官问我:Java虚拟机是怎样运行Java字节码的?这个问题问的我哑口无言,虽然工作了5年,但是做的项目基本都是CRUD,所以只想能做好项目就可以了,管他什么底层,跟我有什么关系?

这次被打脸了,觉得很丢人,所以花了几天时间把JVM看了一遍,终于把Java虚拟机是怎样运行字节码的搞清楚了!

那我们先从HelloWorld 来开始字节码之旅;

Java文件是如何变成.class文件的

新建一个HelloWorld.java文件,代码如下

public class HelloWorld {

public static void main( String[] args ) {

System.out.println("Hello,World");

}

}

Java 从源文件到执行的过程如下图:

ffd3a98424abdc1e7e65ff3fb09bc552.png

JDK的工具javac帮助我们把java文件编译成JVM可识别的class文件,在Java命令行中执行

javac HelloWorld.java,就可以看到生成的HelloWorld.class文件,

那么怎样看生成的16进制呢?

(1) window环境可以下载 winhex 16进制编辑器

(2) Linux环境下

  • 查看class 文件 打开文件 vim HelloWorld.class ,然后输入:%!xxd 就是以16进制显示class文件了
  • 也可以使用Linux下的xxd命令,将二进制信息转换为16进制数据,使用方式为

xxd HelloWorld.class HelloWorld.txt

7325daedb67a77757b3bb59489ea3463.png

那么如何查阅生成的字节码呢?

javap -verbose HelloWorld.class

public com.test.HelloWorld();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=1, locals=1, args_size=1

0: aload_0

1: invokespecial #1 // Method java/lang/Object."":()V

4: return

LineNumberTable:

line 3: 0

LocalVariableTable:

Start Length Slot Name Signature

0 5 0 this Lcom/tuling/test/HelloWorld;

public static void main(java.lang.String[]);

descriptor: ([Ljava/lang/String;)V

flags: ACC_PUBLIC, ACC_STATIC

Code:

stack=2, locals=1, args_size=1

0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;

3: ldc #3 // String Hello,World

5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

8: return

LineNumberTable:

line 5: 0

line 6: 8

LocalVariableTable:

Start Length Slot Name Signature

0 9 0 args [Ljava/lang/String;

}

上面的转换是怎样操作的呢?

我们需要设计一个面向Java语言特性的虚拟机,并通过编译器将Java程序转换成该 虚拟机所能 识别 的指令 序列,也称为java字节码。

Java 为什么可以 一次编写,到处运行

f5740efb475669b90caf402094266e3f.png

Java虚拟机在各个平台(如Window_x64、Linux)上提供软件实现,这么做的意义呢?一旦一个程序被转换成Java字节码,那么它便可以在不同平台上的 虚拟机实现里运行。这就是我们常说的"一次编写,到处运行"。

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

fe3b2c43ca1db26e27f5ef2b5da94ab3.png

(1) 从软件层面上

执行Java代码,首先需要用 javac命令编译成class文件,然后由类加载器加载到虚拟机中,

Java后的java类会被存放于方法区(Method Area)中。实际运行时,虚拟机会执行方法区内的代码。

java 虚拟机会把栈细分为Java方法栈和本地方法栈,以及存放Java指令执行位置的PC寄存器。

f570f285f2635733ad9fbd3fc81315e1.png

下面我们举例说明代码执行过程:

acc6ba82e33754fecb7f209328b590fd.png

对应的字节码如下:

f8ab67739deb806a99007cca4c7cead8.png
b8ab90d6d51c9cc6cbbacaa5b89f41c6.png

执行图如下:

c4acdb1d9ced2a84b53b05e4fe1699a3.png

在运行过程中,每当调用进入一个 Java 方法,Java 虚拟机会在当前线程的 Java 方法栈中生成一个栈帧,用以存放局部变量以及字节码的操作数。这个栈帧的大小是提前计算好的,而且 Java 虚拟机不要求栈帧在内存空间里连续分布。

当退出当前执行的方法时,不管是正常返回还是异常返回,Java 虚拟机均会弹出当前线程的当前栈帧,并将之舍弃。

那么中的动态链接是什么呢?

当程序在运行过程中,执行某一个方法(符号引用),找到方法里的代码

39b7cafcb625dbc13bf36f0d6a36fc06.png
3d58784308a342aa09b78659cdcbda59.png

(2) 从硬件角度上

从硬件的角度上,Java 字节码是无法直接执行的。因此,Java虚拟机会根据不同的系统 将字节码转换为对应的机器码。

字节码是怎么转换为机器码的 呢?有 两种形式

第一种是解释执行,即逐条将字节码翻译成机器码并执行;

第二种是即时编译(Just-In-Time compilation,JIT),即将一个方法中包含的所有字节码编译成机器码后再执行。

5e50b99801894b622601629b4ed4098f.png

前者的优势在于无需等待编译,而后者的优势在于实际运行速度更快。

HotSpot 默认采用混合模式,综合了解释执行和即时编译两者的优点。它会先解释执行字节码,而后将其中反复执行的热点代码,以方法为单位进行即时编译。


如果对你有帮助,欢迎关注@码农的一天,转发!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值