谈谈对Java平台的理解

对Java平台的理解,以及回答一个问题--Java是解释运行的吗?

一、面向对象的语言

1、书写一次,到处运行(Write once,run anywhere)

一次书写,到处运行说的是Java语言的跨平台的特性。当然,从本质上讲Java与其他语言没有差异,只不过因为Java 虚拟机的存在,Java才有了这种特性。严格来讲,跨平台的语言不止Java一种,只不过Java是比较成熟的一个。

学过编译原理我们知道程序由源代码到输出经历了四个阶段-----编码、编译、运行、调试。Java的编译阶段体现了跨平台特性。Java的编译过程大概是这样的:

①首先是通过Javac编译成字节码(bytecode,.class文件),这是第一次编译。.class文件就是可以到处运行的文件。②然后Java字节码会被转化为目标机器代码,这是是由JVM来执行的,即Java的第二次编译。 从上面我们知道Java的到处运行关键是JVM。所以不同的平台,不同的操作系统都有对应的JDK(或者JRE)。

名词解释:

JRE:Java Runtime Environment,也就是Java运行环境,包含了JVM和Java类库、以及一些模块等。

JDK:Java development kit,可以看做是JRE的一个超集,提供了更多工具,比如编译器、各种诊断工具等。

2、垃圾收集(GC,Garbage Collection)

Java通过垃圾回收器回收分配内存大部分情况下,程序员不需要自己操心内存的分配和回收。

最常见的垃圾收集器,有 SerialGC、Parallel GC、 CMS、 G1 等。

3、封装、继承、多态

二、回答一个问题:Java是解释执行的吗?

1、前言

解释执行:将源语言(如python)书写的源程序作为输入,解释一句后就提交计算机执行一句,并不形成目标程序。如同外语翻译中的口译,说一句翻译一句。解释程序执行速度很慢,例如源程序中出现循环,则解释程序也重复地解释并提交执行这一组语句,这就造成很大浪费。

翻译执行:把高级语言(如FORTRAN、COBOL、Pascal、C等)源程序作为输入,进行翻译转换,产生出机器语言的目标程序,然后再让计算机去执行这个目标程序,得到计算结果。

为什么会有《Java是否是解释执行》的问题呢----这是因为解释执行不依赖于平台,因为编译器会根据不同的平台进行解析。

根据上面提到的Java跨平台特性所以才有这个问题。这里提一下,Python编译器是解释编译器,即解释执行的,所以一些大型的计算Python运行速度比C++要慢很多。(在leetcode上,同一种思路,用Python运行TLE,而C++运行则可能会AC)

2、答案

针对Java而言答案是否定的。

在运行时,JVM 会通过类加载器(Class-Loader)加载字节码,解释或者编译执行。主流 Java 版本中,如 JDK 8 实际是解释和编译混合的一种模式,即所谓的混合模式(-Xmixed)。

小拓展(涉及到JVM工作):

通常运行在 server 模式的 JVM,会进行上万次调用以收集足够的信息进行高效的编译,client 模式这个门限是 1500 次。Oracle Hotspot JVM 内置了两个不同的 JIT compiler(Just In Time Compile 即时编译器),C1 对应前面说的 client 模式,适用于对于启动速度敏感的应用,比如普通 Java 桌面应用;C2 对应 server 模式,它的优化是为长时间运行的服务器端应用设计的。默认是采用所谓的分层编译(TieredCompilation)。

Java 虚拟机启动时,可以指定不同的参数对运行模式进行选择。 比如,指定“-Xint”,就是告诉 JVM 只进行解释执行,不对代码进行编译,这种模式抛弃了 JIT 可能带来的性能优势。毕竟解释器(interpreter)是逐条读入,逐条解释运行的。与其相对应的,还有一个“-Xcomp”参数,这是告诉 JVM 关闭解释器,不要进行解释执行,或者叫作最大优化级别。这种模式是不是最高效啊?简单说,还真未必。“-Xcomp”会导致 JVM 启动变慢非常多,同时有些 JIT 编译器优化方式,比如分支预测,如果不进行 profiling,往往并不能进行有效优化。

3、发展

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

jaotc --output libHelloWorld.so HelloWorld.classjaotc --output libjava.base.so --module java.base  然后,在启动时直接指定就可以了。

java -XX:AOTLibrary=./libHelloWorld.so,./libjava.base.so HelloWorld而且,Oracle JDK 支持分层编译和 AOT 协作使用,这两者并不是二选一的关系。

4、总结

针对上面所有总结一下: 不正确!

1、Java源代码经过Javac编译成.class文件

2、.class文件经JVM解析或编译运行。

(1)解析:.class文件经过JVM内嵌的解析器解析执行。 (2)编译:存在JIT编译器(Just In Time Compile 即时编译器)把经常运行的代码作为"热点代码"编译与本地平台相关的机器码,并进行各种层次的优化。 (3)AOT编译器: Java 9提供的直接将所有代码编译成机器码执行。

3、协同合作

(1)只是用解释器的缺点:抛弃了JIT可能带来的性能优势。如果代码没有被JIT编译的话,再次运行时需要重复解析。 (2)只用JIT的缺点:需要将全部的代码编译成本地机器码。要花更多的时间,JVM启动会变慢非常多;增加可执行代码的长度(字节码比JIT编译后的机器码小很多),这将导致页面调度,从而降低程序的速度。 (3)JDK 9引入了一种新的编译模式AOT(Ahead of Time Compilation),它是直接将字节码编译成机器码,这样就避免了JIT预热等各方面的开销。JDK支持分层编译和AOT协作使用。

更多的java基础知识在我的java技术扣扣交流峮里,需要的朋友可以来108中162后1881浏览下载。

相关推荐