谈谈对Java平台的理解

  |  


知其然而不知其所以然

如果谈起对Java的理解,对于这类笼统的问题,或许会稍微紧张一下,有点知其然而不知其所以然的感觉,可能不知从何说起或者回答会有稍微片面,所以今天就点到线地整理一下对Java的理解。


JRE、JDK、JIT、AOT

如果从java的运行开始说起,我们日常会接触到 JRE(Java Runtime Environment)或者 JDK(Java Development Kit)。 JRE,也就是 Java 运行环境,包含了 JVM 和 Java 类库,以及一些模块等。而 JDK 可以看作是 JRE一个超集,提供了更多工具,比如编译器、各种诊断工具等

Write once, run anywhere

还记得当初Java宣传的一句话吗,”Write once, run anywhere”,一次编译,到处执行,体现Java跨平台的特性。

Java的跨平台特性与Java虚拟机的存在密不可分,可在不同的环境中运行;比如说Windows平台和Linux平台都有相应的JDK,安装好JDK后也就有了Java语言的运行环境。其实Java语言本身与其他的编程语言没有特别大的差异,并不是说Java语言可以跨平台,而是在不同的平台都有可以让Java语言运行的环境而已,所以才有了Java一次编译,到处运行这样的效果。

众所周知,我们通常把Java分为编译期和运行时。这里说的Java的编译和C/C++是有着不同的意义的,Javac的编译,编译Java源码生成 .class 字节码文件,这个字节码文件是可以到处运行的,这是第一次编译;然后这个字节码文件就由JVM来进行第二次编译,转换成目标的机器代码,这就体现了跨平台特性,这个过程也是叫作Java解释执行

跟C/C++最大的不同点在于,C/C++编程是面向操作系统的,需要开发者极大地关系不同操作系统之间的差异性;而Java平台通过JVM虚拟机屏蔽了操作系统和硬件的底层细节,使得开发者无需过多地关心不同操作系统之间的差异性。通过增加一个间接的中间层来进行“解耦”,是计算机领域非常常用的一种“艺术手法”,JVM虚拟机是这样,操作系统是这样,Http也是这样。

  • Java解释执行:我们开发的Java的源代码,首先通过Javac编译成字节码(bytecode),然后运行的时通过Java虚拟机(JVM)内嵌的解释器将字节码转换成最终的机器码,这就属于Java解释执行
  • Java编译执行:当我们常见的JVM,比如Oracle JDK提供的Hotspot JVM,都提供了JIT(Just-In-Time)编译器,也就是通常所说的动态编译器,JIT能够在运行时将热点代码编译成机器码,这种情况下部分热点代码就属于编译执行

在运行时,JVM会通过 类加载器(Class-Loader) 加载字节码,解释或者编译执行,就像前面提到的,主流Java版本中,如JDK8实际是解释和编译混合的一种模式,即所谓的混合模式(-Xmixed)。通过运行在server模式的JVM,会进行上万次调用以收集足够的信息进行高效的编译,client模式这个门限是1500次。Oracle Hotspot JVM 内置了两个不同的 JIT compiler,C1 对应前面说的 client 模式,适用于对于启动速度敏感的应用,比如普通Java应用;C2 对应server模式,他的优化是为长时运行的服务端应用设计的。默认是采用所谓的 分层编译(TieredCompilation)

  • Java 虚拟机启动时,可以指定不同的参数对运行模式进行选择。

    • 比如,指定“-Xint”,就是告诉 JVM 只进行解释执行,不对代码进行编译,这种模式抛弃了 JIT 可能带来的性能优势。毕竟解释器(interpreter)是逐条读入,逐条解释运行的。

    • 与其相对应的,还有一个“-Xcomp”参数,这是告诉 JVM 关闭解释器,不要进行解释执行,或者叫作最大优化级别。那你可能会问这种模式是不是最高效啊?简单说,还真未必。“-Xcomp”会导致 JVM 启动变慢非常多,同时有些 JIT 编译器优化方式,比如分支预测,如果不进行 profiling,往往并不能进行有效优化。

除了我们日常最常见的 Java 使用模式,其实还有一种新的编译方式,即所谓的 AOT(Ahead-of-Time Compilation)直接将字节码编译成机器代码,这样就避免了 JIT 预热等各方面的开销,比如 Oracle JDK 9 就引入了实验性的 AOT 特性,并且增加了新的 jaotc 工具。利用下面的命令把某个类或者某个模块编译成为 AOT 库。(也就是可以直接把java代码编译成机器代码运行)

1
2
jaotc --output libHelloWorld.so HelloWorld.class
jaotc --output libjava.base.so --module java.base

然后,在启动时直接指定就可以了。

1
java -XX:AOTLibrary=./libHelloWorld.so,./libjava.base.so HelloWorld

而且,Oracle JDK 支持分层编译和 AOT 协作使用,这两者并不是二选一的关系。如果你有兴趣,可以参考相关文档:http://openjdk.java.net/jeps/295。AOT 也不仅仅是只有这一种方式,业界早就有第三方工具(如 GCJ、Excelsior JET)提供相关功能。


知识扩展

  1. 对于 Java 平台的理解,可以从很多方面简明扼要地谈一下,

    • 例如:Java 语言特性,包括泛型、Lambda 等语言特性;基础类库,包括集合、IO/NIO、网络、并发、安全等基础类库。
    • 对于我们日常工作应用较多的类库,面试前可以系统化总结一下,有助于临场发挥。
  2. 或者谈谈 JVM 的一些基础概念和机制,比如 Java 的类加载机制,常用版本 JDK(如 JDK 8)内嵌的 Class-Loader,例如 Bootstrap、 Application 和 Extension Class-loader;

    • 类加载大致过程:加载、验证、链接、初始化(这里参考了周志明的《深入理解 Java 虚拟机》,非常棒的 JVM 上手书籍);自定义 Class-Loader 等。
    • 还有垃圾收集的基本原理,最常见的垃圾收集器,如 SerialGC、Parallel GC、 CMS、 G1 等,对于适用于什么样的工作负载最好也心里有数。
  3. 当然还有 JDK 包含哪些工具或者 Java 领域内其他工具等,如编译器、运行时环境、安全工具、诊断和监控工具等。这些基本工具是日常工作效率的保证,对于我们工作在其他语言平台上,同样有所帮助,很多都是触类旁通的。

下图是总结的一个相对宽泛的蓝图提供参考。

Copyright © 2018 - 2020 Kuanger All Rights Reserved.

访客数 : | 访问量 :