Java代码如何运行起来?

南风 2020年10月21日 75次浏览

Java代码运行流程图

一、Java的口号

一次编译,到处运行。

二、Java运行的基本流程

  • 1、Java Code编译成.class文件;
  • 2、.class文件后装载到JVM;
  • 3、利用JVM对其进行解释转化成机器码,操作系统执行机器码。

三、对于一个具体的Java方法又是什么运行呢?

  • 1、Java代码文件编译成Java字节码file.class文件;
  • 2、运行Java file.class命令;
  • 3、加载系统JDK jre,寻找jvm.cfg文件,通过-server判断虚拟机服务是否可用;
  • 4、通过jvm.cfg文件找到jvm.dll,jvm.dll是JVM的主要实现;
  • 5、jvm.dll调用JNI接口,执行main方法逻辑。

四、JVM体系结构

  • 类装载器ClassLoader:用来装载.class文件
  • 执行引擎:执行字节码,或者执行本地方法
  • 运行时数据区:方法区、堆、Java栈、程序计数器、本地方法栈

1、类装载器ClassLoader

类装载器

  • 装载三动作

    • 1.通过“类全名”来获取定义此类的二进制字节流
    • 2.将字节流所代表的静态存储结构转换为方法区的运行时数据结构
    • 3.在java堆中生成一个代表这个类的java.lang.Class对象,作为方法区这些数据的访问入口
  • 验证四阶段

    • 文件格式验证
    • 元数据验证
    • 字节码验证
    • 符号引用验证
  • 准备类变量初始化
    类变量分配内存并设置类变量初始值。内存于方法区

  • 解析四引用
    解析的动作主要针对类或接口、字段、类方法、接口方法四类符号引用进行。

  • 初始化
    类加载最后阶段,若该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化成员变量。

2、执行引擎

执行引擎负责具体的代码调用及执行过程。

  • 输入:字节码文件
  • 处理:字节码解析
  • 输出:执行结果。
    执行引擎必须把字节码转换成可以直接被JVM执行的语言,可以通过解释器和即时解释器来转化。

3、运行时数据区

  • 方法区——线程共享
    有时候也称为永久代(Permanent Generation),在方法区中,存储了每个类的信息(包括类的名称、修饰符、方法信息、字段信息)、类中静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息以及编译器编译后的代码等。

  • 堆——线程共享
     Java中的堆是用来存储对象实例以及数组(当然,数组引用是存放在Java栈中的)。堆是被所有线程共享的,因此在其上进行对象内存的分配均需要进行加锁,这也导致了new对象的开销是比较大的。在JVM中只有一个堆。堆是Java垃圾收集器管理的主要区域,Java的垃圾回收机制会自动进行处理。
     堆空间分为老年代和年轻代。刚创建的对象存放在年轻代,而老年代中存放生命周期长久的实例对象。年轻代中又被分为Eden区和两个Survivor区(From Space和To Space)。新的对象分配是首先放在Eden区,Survivor区作为Eden区和Old区的缓冲,在Survivor区的对象经历若干次GC仍然存活的,就会被转移到老年代。 当一个对象大于eden区而小于old区(老年代)的时候会直接扔到old区。 而当对象大于old区时,会直接抛出OutOfMemoryError(OOM)。

  • Java栈(虚拟机栈)——线程私有
    Java栈是Java方法执行的内存模型。Java栈中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法,在栈帧中包括局部变量表(Local Variables)、操作数栈(Operand Stack)、指向当前方法所属的类的运行时常量池的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些额外的附加信息。当线程执行一个方法时,就会随之创建一个对应的栈帧,并将建立的栈帧压栈。当方法执行完毕之后,便会将栈帧出栈。因此可知,线程当前执行的方法所对应的栈帧必定位于Java栈的顶部。

  • 程序计数器——线程私有
    程序计数器(Program Counter Register),也有称作为PC寄存器。由于在JVM中,多线程是通过线程轮流切换来获得CPU执行时间的,因此,在任一具体时刻,一个CPU的内核只会执行一条线程中的指令,因此,为了能够使得每个线程都在线程切换后能够恢复在切换之前的程序执行位置,每个线程都需要有自己独立的程序计数器,并且不能互相被干扰,否则就会影响到程序的正常执行次序。因此,可以这么说,程序计数器是每个线程所私有的。

  • 本地方法栈——线程私有
    JVM采用本地方法堆栈来支持native方法的执行,此区域用于存储每个native方法调用的状态。本地方法栈与Java栈的作用和原理非常相似。区别只不过是Java栈是为执行Java方法服务的,而本地方法栈则是为执行本地方法(Native Method)服务的。在JVM规范中,并没有对本地方法栈的具体实现方法以及数据结构作强制规定,虚拟机可以自由实现它。在HotSopt虚拟机中直接就把本地方法栈和Java栈合二为一。

(全文完)