Java被称为是一个人类可读的编程语言,其主要特点是基于类和面向对象,Java的开源版本被称为OpenJDK。Java编程环境由两个部分组成:Java语言和运行环境,运行环境也称为Java虚拟机(JVM),JVM是一个为执行Java程序提供运行时环境的程序。本文主要探讨JVM的实现机制。
什么是JVM解释之前,先上一张图吓一下大家:
这张图中我们需要注意的是,JVM的核心组件包括三个部分:Heap, JIT Compiler, GC, 当我们要优化JVM的性能的时候主要调优的目标是这三个组件。
JVM负责解释执行字节码文件,所有平台上的JVM向编译器提供相同的编程接口,而编译器只需要面向虚拟机,生成虚拟机能理解的代码,然后由虚拟机来解释执行。JVM是一个为执行Java程序提供运行时环境的程序。没有JVM,Java程序也就不能执行。一个Java程序通常通过以下的方式执行:
java <arguments> <program name>
首先操作系统会启动JVM进程为Java程序提供运行时环境,然后会在刚启动的虚拟机中执行我们的Java程序。需要注意的是,Java程序首先要被转换(编译)成Java字节码(bytecode),JVM上运行的是Java字节码程序。JVM可以看成是一个JAVA字节码程序解释器。
Write Once, Run anywhere
当使用Java编译器编译Java程序时,生成的是与平台无关的字节码,这些字节码不面向任何具体平台,它只面向JVM。不同平台的JVM都是不同的,但它们都提供了相同的接口。JVM是Java程序跨平台的关键部分,只要为不同平台实现了相应的虚拟机,编译后的Java字节码就可以在该平台上运行。
JVM收集运行时信息以为如何执行代码做出更好的决策。这意味着JVM能够自动模拟和优化运行在它上面的程序。JVM在Java程序和操作系统间形成了一个中间层,使得开发者不用过多的处理和操作系统相关的具体细节问题。
JVM的另一个好处是,任何能够编译成字节码的语言都可以在它上面运行,不仅仅是Java,比如Groovy, Scala和Clojure这些基于JVM的语言。这也意味着,这些语言可以轻松的使用其他语言写的函数库。例如一个Scala开发者可以调用Java库,因为他们运行在相同的平台上。
从实际硬件上隔离出来,意味着Java代码就像一个沙盒,这可以避免一运行有害代码对机器硬件造成的伤害。安全性是JVM的主要好处之一。需要注意的是,并不是所有的JVM都是相同的,在Oracle的标准JVM实现标准之上还存在很多其他的实现方式。而我们主要讨论的是HotSport JVM,这也是OpenJDK和Oracle JVM的实现基础。
JIT - Just In Time正如我们之前讨论的,JVM运行的是字节码。但是,如果有一段代码会被频繁的执行,那么JVM可以决定将这段代码编译为机器码(native code)以加快这段代码的执行速度。JIT可编译的最小执行块是一个方法。默认情况下,一个代码块需要被执行1500次才会被JIT编译,这个次数是可配置的。利用JIT机制可以有效的提升系统的性能,但是,JIT编译并不是无代价的,其需要耗费额外的系统资源和时间。
Java内存管理和GC在Java中,对象所占用的内存在对象不再使用后会自动被回收。这些工作是由一个叫垃圾回收器Garbage Collector的进程完成的。相比较C/C++程序而言,你必须手动调用free()函数或delete操作符来回收内存。在这里我们主要讨论的是HotSpot JVM(这也是OpenJDK和Oracle Java的实现基础),事实上,还有很多其他的JVM实现方式。
GC的优缺点好处是
开发者无需过问内存管理,可以专注于解决实际问题。虽然内存泄露仍有可能会发生,但发生的概率比较小。
GC的智能算法可以在后台自动的进行内存管理,且这种管理在大多数时候是最佳的。
坏处是
当垃圾回收发生时,它会影响程序的性能,甚至会暂停程序的执行。这个被称为“Stop the world”垃圾回收机制,整个程序进程会被暂停以等待垃圾回收执行完。对某些应用而言,这可能是无法接受的。
开发者并不能指定何时或使用何种方法执行GC。
Generational GC在了解更多关于GC的问题之前有必要理解Java内存中的堆区(Heap)事如何工作的。所有的对象都存在于堆中(与此对应的是栈,这里初访者变量和方法,以及堆中对象的引用)。垃圾回收的过程也就是将堆区中不再需要对象清除的过程。几乎所有的GCs都是“分代的(generational)”,也就是说堆区会划分成很多的区块,也称为代。Hotspot的堆结构如下图所示: