JVM系列:(一)Java代码是怎么运行的

日期:2019-01-16       浏览:502

一 JDK 组成架构

1.1 图解

JDK组成架构
JDK组成架构

1.2 描述

上图的 JDK 组成架构可以看出,JDK 由两部分组成。
一部分是 Java 工具包:javac、jar、javadoc等。
  • javac:编译器,将源程序 .java 编译成字节码 .class 文件;
  • jar:打包工具,将相关的类文件或第三方jar包打包成一个 jar 文件;
  • javadoc:文档生成器,从源码中将符合 javadoc 规范的注释提取文档;
还有一部分是 Java 程序运行的标准环境 JRE(Java Runtime Environment):JVM、Java核心类库。
  • JVM:Java 虚拟机,编译后的 .class 字节码文件的运行平台。
  • Java核心类库:Java SE API子集(包括 java.lang包、java.io包、java.util包等)下的所有类。

二 Java文件的编译执行

2.1 图解

Java文件的编译-打包-运行数据流图
Java文件的编译-打包-运行数据流图

2.2 描述

从上图可以看出,从我们写的 .java 源程序到最后运行结束的整个生命周期内,有以下几个关键性的步骤:编译、打包、类加载、创建对象、方法调用、多线程上下文切换、类卸载。接下来我们就说一下每一步的输入和执行结果;
  • 编译:通过 javac 编译工具将 .java 的源程序文件编译为 .class 的字节码文件,因为 JVM 只认识 .class 字节码。Java 程序的跨平台能力(Write once, Run Anywhere)也是在这里,因为不同平台的 JVM 对底层操作系统的实现上不同,但是对输入的内容要求都是 .class 字节码文件,这也就是我们编译后的 .class 文件可以在不同平台的 JVM 上正常运行的原因所在。
  • 打包:一个完整的项目不可能只是一个 .class 文件就可以完成的,需要多个 .class 文件,可能还需要依赖多个外部的第三方 jar 包(Java有一套完整的应用程序接口,还有无数来自商业机构和开源社区的第三方类库来帮助你实现各种各样的功能),但是一个项目的入口文件只有一个,这时就需要把多个 .class 文件、多个 jar 包等打包为一个 jar 或 war 包,并指定入口文件地址。这里用到的打包工具就是JDK自带的 jar 工具了。
  • 类加载:JVM找到项目的入口文件,启动应用程序,并通过项目运行过程中的相关依赖加载其他 .class 文件的过程就是类加载。加载后的 .class 文件保存在JVM的方法区,是所有线程共享的区域,在加载的过程中会初始化类常量,在JVM的堆内存中保存对应加载类的class对象相关信息等。
  • 创建对象:Java是面向对象的程序设计语言,程序的运行也是以对象为调用单位,在运行的过程中需要通过加载在方法区的 .class 字节码文件创建与其对应的对象信息。创建对象的方式有:new关键字,反射等,创建后的对象信息保存在JVM的堆内存中,是所有线程共享的区域,也是垃圾回收的主要区域(JVM提供了一个相对安全的内存管理和访问机制,避免了绝大部分的内存泄露和指针越界的问题)。
  • 方法调用:JVM的调用单位是对象,但是真正执行功能性的代码却是对象上的方法,当调用某个对象的某个方法时,JVM执行引擎会将对应方法的 .class 字节码文件通过解释执行或即时编译(执行引擎实现了热点代码检测和运行时编译及优化,这使得Java应用能随着运行时间的增加而获得更高的性能)的方式再次编译为计算机所能识别的机器码(.class字节码是JVM所能识别的文件,计算机能识别的只有机器码),编译后的机器码信息存储在方法区内存中。对该方法生成一个方法帧,根据是否是c++ 实现的native方法压栈到本地方法栈或Java方法栈,方法调用完成再出栈结束调用。方法栈内存是线程私有的,每个线程都有自己的方法栈。
  • 多线程上下文切换:Java是一门多线程编程语言,在应用运行的过程中CPU会进行不同线程间的切换调度,如果当前线程还在运行中,这时CPU告诉它“你运行的时间结束了,换下一个”,但是已经运行过的结果信息是需要保存的,不然这之前的工作岂不是白做了。这时就需要将当前要结束的线程的上下文信息保存起来,保存到JVM的PC寄存器(程序计数器)中,这块的内存是当前线程私有的,不会被其他线程修改。当下次CPU再通知当前线程说“别等了,该你执行了”的时候,当前线程只需要把PC寄存器中的数据恢复,接着上一次执行到的位置继续执行就好了。
  • 类卸载:当堆内存中的某个对象执行完成并且没有其他可运行的对象在引用它时,这个对象就会被垃圾回收线程从堆内存中删除,并且释放掉该对象所占用的内存空间。被垃圾回收掉的对象对应的方法区 .class 字节码文件也需要被删除掉,这就是类卸载。
作为一名Java程序员,在编写程序时除了尽情发挥Java的各种优势外,还应该去了解和思考一下Java技术体系中这些技术特性是如何实现的,认识这些技术运作的本质,是自己思考“程序这样写好不好”的基础和前提。
接下来我们会通过图文并茂的方式,按照Java代码在JVM中的执行顺序展开讲解。主要涉及内容有Java基本数据类型、编译打包、JVM内存模型、类加载、构造对象、执行引擎、异常处理、垃圾收集、类卸载等。
扫码关注有惊喜

(转载本站文章请注明作者和出处 qbian)

暂无评论

Copyright 2016 qbian. All Rights Reserved.

文章目录