文章目录

  • 前言
  • 案例
  • 加载至JVM内存
  • CPU执行指令


前言

在之前的JVM专栏中具体说明了各个JVM内存区域的信息、功能作用等。以及讲到了jdk不同版本针对GC操作使用垃圾收集器的区别等。

相信大家对一个Java程序的执行过程还是有点好奇的。

本篇博客就从Java程序到计算机CPU执行这个过程做一个介绍和说明。

案例

假设需要执行下列案例:

public class Math {

    public void test(){
        int a = 0;
        int b = 5;
        System.out.println(a+b);
    }

    public static void main(String[] args) {
        Math td = new Math();
        td.test();
    }
}

加载至JVM内存

一个.java程序在执行之前,需要将其转化为.class字节码文件,加载至jvm中,然后让计算机去执行。其加载过程图如下所示:

java 指定cpu运行 java中cpu是怎么被使用的_JVM


其中,JVM将.class文件信息加载至JVM虚拟机中的过程,使用的是JVM的类装载子系统,其执行操作如下所示:

java 指定cpu运行 java中cpu是怎么被使用的_字节码_02


xx.class类中的类执行了加载操作后,会将其中的类元信息加载至JVM的方法区中,如下所示:

java 指定cpu运行 java中cpu是怎么被使用的_JVM_03


【疑问:】哪些是类元信息?

使用命令 javap -v Math.class 执行后,下列的Constant pool 即为类元信息,

java 指定cpu运行 java中cpu是怎么被使用的_加载_04

方法区主要保存常量 final(包含常量池)静态变量 static类元信息(类的常量池)

当执行main方法时,会在栈中开辟一块区间,存放相应的信息。

main是程序的入口,也是一个线程。

执行实例化new Math()操作,会在堆中创建实例化对象地址信息。并将栈中的td 局部变量,针对堆中的Math实例对象地址进行引用。

java 指定cpu运行 java中cpu是怎么被使用的_字节码_05


当采取td.test()调用实例化对象中的指定方法时,此时则需要借用字节码执行引擎实现相关操作,如下所示:

首先,会在中分配一块内存区域,创建main线程。

其次,引用test(),则继续在对应栈内存中压入test()

在执行test()中的程序逻辑时,会依次对其中的指令进行操作。

java 指定cpu运行 java中cpu是怎么被使用的_字节码_06

这个指令是操作数栈中的操作数值临时存放

java 指定cpu运行 java中cpu是怎么被使用的_java 指定cpu运行_07

此时每条指令均由字节码执行引擎进行相应的操作。但此时的操作仅仅只是内存层面的数据操作,指令的计算赋值等依旧需要cpu去执行实现。

CPU执行指令

字节码执行引擎获取需要执行的每条指令,通过解释执行器/JIT优化将指令进行翻译操作,将其翻译成汇编指令

字节码执行引擎JVM层面的技术,但是计算机执行命令,只认二进制命令

JVM中通常使用解释执行器或者JIT优化器,将jvm 层面的 字节码信息翻译成汇编指令

汇编指令属于硬件原语,此时并不能直接被CPU进行执行。

依旧需要借用硬件层面翻译操作,将汇编指令转化为cpu可识别的 二进制指令。等待CPU的调度执行,最后影响对应栈中的数据信息

具体操作逻辑如下图所示:

java 指定cpu运行 java中cpu是怎么被使用的_java 指定cpu运行_08


查询 JVM指令手册 可知iconst_0的含义为:

CPU处理iconst_0的操作含义后,将常量0 压入对应的中。


这个指令执行完成后,在继续执行下列其他指令。

java 指定cpu运行 java中cpu是怎么被使用的_字节码_09