JVM那些事儿之执行原理(二)

本文探讨了JVM执行Java程序的过程,从编译 HelloWorld 程序到JVM如何解释执行字节码。JVM主要由C/C++编写,采用函数指针技术执行机器码。早期因速度慢受批评,但现在通过优化已能与C/C++媲美。文章还提到了类装载子系统、GC子系统、内存区和执行引擎的工作原理。

JVM那些事儿之执行原理(二)

案例

当一个java程序员把第一个helloworld程序敲出来后,它是怎么在console里打印出“helloworld”的?

编写Java程序

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println(“hello world!”);
    }
}

通过javac将.java文件编译成.class字节码文件

> javac HelloWorld.java

使用 javap查看.class字节码文件

> javap -verbose HelloWorld.class

此时可以看到这样一个字符串。这个字符串就是编译后的内容

Classfile /jvmtest/HelloWorld.class
  Last modified 2017-8-12; size 426 bytes
  MD5 checksum 4efac412ef483c8a3fe7489c87d15c8c
  Compiled from "HelloWorld.java"
public class HelloWorld
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#15         // java/lang/Object."<init>":()V
   #2 = Fieldref           #16.#17        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #18            // hello world!
   #4 = Methodref          #19.#20        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = Class              #21            // HelloWorld
   #6 = Class              #22            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               main
  #12 = Utf8               ([Ljava/lang/String;)V
  #13 = Utf8               SourceFile
  #14 = Utf8               HelloWorld.java
  #15 = NameAndType        #7:#8          // "<init>":()V
  #16 = Class              #23            // java/lang/System
  #17 = NameAndType        #24:#25        // out:Ljava/io/PrintStream;
  #18 = Utf8               hello world!
  #19 = Class              #26            // java/io/PrintStream
  #20 = NameAndType        #27:#28        // println:(Ljava/lang/String;)V
  #21 = Utf8               HelloWorld
  #22 = Utf8               java/lang/Object
  #23 = Utf8               java/lang/System
  #24 = Utf8               out
  #25 = Utf8               Ljava/io/PrintStream;
  #26 = Utf8               java/io/PrintStream
  #27 = Utf8               println
  #28 = Utf8               (Ljava/lang/String;)V
{
  public HelloWorld();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0

  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 3: 0
        line 4: 8
}
SourceFile: "HelloWorld.java"

执行.class文件

> java HelloWorld

此时控制台会打印出

> hello world!

执行原理

如何生成.class文件咱们先不讲,反正文件是有了。咱们就来讲讲拿到这个文件后,JVM在执行这个文件时的过程。

先说明一下JVM到底是什么语言开发的?Java的解释器肯定不是Java开发了,其实,JVM主要是C/C++开发的,里面还有很多汇编语言。我们在执行.class文件时采用的方式是解释执行。

我们先说一个最精简的原理。
前面我们已经看到.class文件里面,会分成不同的方法。JVM在解释的时候,先把内存什么的规划好(具体怎么规划的后面讲),然后大概看一下有哪些方法,把这些方法都转换成机器码保存起来。当JVM自检结束后,将会先从main方法开始执行。

具体执行依赖的是C/C++的函数指针技术,这个技术让JVM可以直接执行一段机器码,而前面我们已经把Java的方法都转换成机器码保存起来了,这时候利用这个技术直接执行机器码就好了。

大家注意了,前面说的这段算是JVM最精彩的部分,为什么呢?刚开始的JVM可不是这样的,所以Java刚出来的时候,由于执行速度慢,被大家诟病,后来改了这个方案后,再加上将字节码转换成机器码的过程不断改进、优化,现在的Java程序在某些方面已经达到甚至超越了C/C++的速度。

以后再有人跟你说java速度慢,你就可以怼回去了。

体系结构

  • 类装载子系统

    负责把类从文件系统中装入内存

  • GC子系统

    垃圾收集器的主要工作室自动回收不再运行的程序引用对象所占用的内存,此外,它还可能负责那些还在使用的对象,以减少的堆碎片。

  • 内存区

    用于存储字节码,程序运行时创建的对象,传递给方法的参数,返回值,局部变量和中间计算结果。

  • 执行引擎

    1、最简单的:一次性解释字节码。
    2、快,但消耗内存的:“即时编译器”,第一次被执行的字节码会被编译成机器代码,放入缓存,以后调用可以重用。
    3、自适应优化器,虚拟机开始的时候会解释字节码,但是会监视运行中程序的活动,并记录下使用最频繁的代码段。程序运行的时候,虚拟机只把使用最频繁的代码编译成本地代码,其他的代码由于使用的并不频繁,继续保留为字节码–由虚拟机继续解释他们。一般可以使java虚拟机80%~90%的时间里执行被优化过的本地代码,只需要编译10%~20%对性能优影响的代码。
    4、由硬件芯片组成,他用本地方法执行java字节码,这种执行引擎实际上是内嵌在芯片里的。
    图示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值