javase基础回顾(五) 对java平台的理解

java有两个特性。一是所谓的“书写一次,到处运行”(Write once, run anywhere),能够非常容易地获得跨平台能力;另外就是垃圾收集(GC, Garbage Collection),Java 通过垃圾收集器(Garbage Collector)回收分配内存,大部分情况下,程序员不需要自己操心内存的分配和回收。今天对前者进行简单的学习记录。

我们开发的 Java 的源代码,首先通过 Javac 编译成为字节码(bytecode),然后,在运行时,通过 Java 虚拟机(JVM)内嵌的解释器将字节码转换成为最终的机器码,由此实现了java的跨平台特性。但是常见的 JVM,比如我们大多数情况使用的 Oracle JDK 提供的 Hotspot JVM,都提供了 JIT(Just-In-Time)编译器,也就是通常所说的动态编译器,JIT 能够在运行时将热点代码编译成机器码,这种情况下部分热点代码就属于编译执行,而不是解释执行了。那么java到底是编译型还是解释型?

众所周知,我们通常把 Java 分为编译期和运行时。这里说的 Java 的编译和 C/C++ 是有着不同的意义的,Javac 的编译,编译 Java 源码生成“.class”文件里面实际是字节码,而不是可以直接执行的机器码。Java 通过字节码和 Java 虚拟机(JVM)这种跨平台的抽象,屏蔽了操作系统和硬件的细节,这也是实现“一次编译,到处执行”的基础。

java的执行过程是,首先通过javac编译java源代码为字节码,然后JVM将这些字节码文件加载进来,加载进来一句,就解释一句,解释出来一句就执行一句,相当于是解释和执行是同步执行的,这种模式被称为解释执行。需要明确的一点:解释执行这个过程并不会产生目标文件,也就是说这些可以被平台执行的机器码文件并没有生成,下次如果还是这部分代码被执行的时候,还需要重新的被解释一遍,这样每次都重复这个过程就会很耗时,因此java引入了JIT,(在程序运行时) 将那些执行比较频繁的代码,也被称作热点代码,编译成为机器码,这个时候其实内存中是保存了一部分这部分机器码的,这样就解决了上面所描述的问题。但是因为JIT是运行时将字节码文件编译成为机器码文件,所以会占用运行时资源,造成进程卡段,所以相对的java中还存在AOT(静态编译),就是在程序运行之前就将字节码编译成为机器码,不会占用到运行时的CPU资源。

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

知识点:

解释执行:将编译好的字节码一行一行地翻译为机器码执行。
编译执行:以方法为单位,将字节码翻译为可重复执行的机器码并保留在内存中。

举个例子相当于同声传译和录音机。

原文地址:https://www.cnblogs.com/Vdiao/p/13211089.html