对java平台的理解

        java本身是一种面向对象的语言,最显著的特性有两个方面,一是所谓的 “书写一次,导出运行” ,能够非常容易地获得跨平台的能力;另外就是垃圾收集,java通过垃圾收集器回收分配内存,大部分情况下,程序员不需要自己操心内存的分配和回收。

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

        有些人认为“java是解释执行”,对于这个说法,我认为不太准确,因为我们开发的java源代码,首先通过javac编译成为字节码,然后,在运行时,通过java虚拟机(JVM)内嵌的解释器将字节码转换为最终的机器码。但是常见的JVM,比如我们大多数情况下使用的Oracle JDK提供的Hotspot JVM,都提供了JIT(Just-In-Time)编译器,也就是通常所说的动态编译器,JIT能够在运行时将热点代码编译成机器码,这种情况下部分热点代码就属于编译执行,而不是解释执行了。

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

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

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

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

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

jaotc --output libHelloWorld.so HelloWorld.class

jaotc --output libjava.base.so --module java.base

扫描二维码关注公众号,回复: 2408260 查看本文章

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

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

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

    另外,JVM作为一个强大的平台,不仅仅只有java语言可以运行在JVM上,本质上合规的字节码都可以运行,java语言自身也为此提供了便利,我们可以看到类似Clojure、Scala、Groovy、JRuby、Jython等大量JVM语言,活跃在不同的场景。

猜你喜欢

转载自blog.csdn.net/dd2016124/article/details/81221067