谈谈对java平台的理解

从接触java到开发到现在,你对java最直观的印象是什么呢?是它宣传的“write once,run anywhere”,还是目前看已经有些过于形式主语的语法呢?你对于java平台到底了解到什么程度?请先停下来总结思考一下。

今天要讨论的是,谈谈你对java平台的理解,“java是解释执行”,这句话对吗?

典型的回答是:

java本省是一种面向对象的语言,最显著地特性有两个方面,以是所谓的一次书写,到处运行(write once,runanywhere),能够非常容易的获得跨平台能力;另外就是垃圾收集(GC,Garbage Collection),java通过垃圾收集器(garbage collector)回收分配内存,大部分情况下,程序员不需要自己操心内存的分配和回收。

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

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

考点分析:

其实这个问题,问的有点笼统。题目本事是非常开放的,往往考察的是多个方面,比如,基础知识理解是否很清楚;是否掌握java平台主要模块和运行原理等。很多面试者会在这种问题上吃亏,稍微紧张了一下,不知道从和说起,就给出个很简单的回答。

对应这类笼统的问题,你需要尽量表现出自己的思维深入并系统化,java只是理解的也比较全面,一定要避免让面试管觉得是个“知其然而不知其所以然”的人。比较明白基本组成和机制,是日常工作中进行问题诊断或者性能挑优等很多事情的基础,详细没有招聘方会不喜欢“热爱学习和思考”的面试者。

只是扩展:

回归正题,对于java平台的理解,可以从很多方面简明扼要的谈一下,例如:java语言特性,包括泛型、Lambda等语言特性;基础类库,包括集合、IO/NIO、并发、安全等基础类库。

对于我们日常工作中用的较多的类库,面试前可以洗头总结一下,有助于临场发挥。

或者谈谈JVM的一些基础概念和机制,比如Java的类加载机制,常用版本JDK(如JDK8)内嵌的class-loader,例如Bootstrap、Application和Extension Class-loader;类加载大致过程:加载、验证、链接、初始化(参考周志明 《深入理解java虚拟机》,非常棒的jvm上手书籍);自定义Class-loader等。还有垃圾收集的基本原理,最常见的垃圾收集器,如SerialGC、Parallel GC、CMS、G1等,对于使用于什么样的工作负载最好也心里有数。这些都是可以扩展的领域。

当然还有JDK包含哪些工具或者java领域内其他工具,如编译器、运行时环境、安全工具、诊断和监控工具的那个。这些基本工具是日常工作效率的保证,对于我们工作再其他语言平台上,荣阳有所帮助,很多都是触类旁通的。

下图是一个相对宽泛的蓝图,供参考:


不再扩展了,回到前面问到的解释执行和编译执行的问题。有些面试官喜欢在特定问题上“刨根问底儿”,因为这是进一步了解面试者对知识掌握程度的有效方法,我稍微深入探讨一下。


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


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


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


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


jaotc --output libHelloWorld.so HelloWorld.class 

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



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


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 语言,活跃在不同的场景。


今天,我简单介绍了一下 Java 平台相关的一些内容,目的是提纲挈领地构建一个整体的印象,包括 Java 语言特性、 核心类库与常用第三方类库、Java 虚拟机基本原理和相关工具,希望对你有所帮助。



优秀回答:

版本1:
“一次编译、到处运行”说的是Java语言跨平台的特性,Java的跨平台特性与Java虚拟机的存在密不可分,可在不同的环境中运行。比如说Windows平台和Linux平台都有相应的JDK,安装好JDK后也就有了Java语言的运行环境。其实Java语言本身与其他的编程语言没有特别大的差异,并不是说Java语言可以跨平台,而是在不同的平台都有可以让Java语言运行的环境而已,所以才有了Java一次编译,到处运行这样的效果。
严格的讲,跨平台的语言不止Java一种,但Java是较为成熟的一种。“一次编译,到处运行”这种效果跟编译器有关。编程语言的处理需要编译器和解释器。Java虚拟机和DOS类似,相当于一个供程序运行的平台。
程序从源代码到运行的三个阶段:编码——编译——运行——调试。Java在编译阶段则体现了跨平台的特点。编译过程大概是这样的:首先是将Java源代码转化成.CLASS文件字节码,这是第一次编译。.class文件就是可以到处运行的文件。然后Java字节码会被转化为目标机器代码,这是是由JVM来执行的,即Java的第二次编译。

“到处运行”的关键和前提就是JVM。因为在第二次编译中JVM起着关键作用。在可以运行Java虚拟机的地方都内含着一个JVM操作系统。从而使JAVA提供了各种不同平台上的虚拟机制,因此实现了“到处运行”的效果。需要强调的一点是,java并不是编译机制,而是解释机制。Java字节码的设计充分考虑了JIT这一即时编译方式,可以将字节码直接转化成高性能的本地机器码,这同样是虚拟机的一个构成部分。

版本2:

我对『Compile once, run anywhere』这个宣传语提出的历史背景非常感兴趣。这个宣传语似乎在暗示 C 语言有一个缺点:对于每一个不同的平台,源代码都要被编译一次。我不解的地方是,为什么这会是一个问题?不同的平台,可执行的机器码必然是不一样的。源代码自然需要依据不同的平台分别被编译。 我觉得真正问题不在编译这一块,而是在 C 语言源文件这一块。我没有 C 语言的编程经验,但是似乎 C 语言程序经常需要调用操作系统层面的 API。不同的操作系统,API 一般不同。为了支持多平台,C 语言程序的源文件需要根据不同平台修改多次。这应该是一个非常大的痛点。我回头查了一下当时的宣传语,原文是『Write once, run anywhere』,焦点似乎并不在编译上,而是在对源文件的修改上。

以上是自己一点不成熟的想法,还请大家指正!

版本3:

Java特性:
面向对象(封装,继承,多态)
平台无关性(JVM运行.class文件)
语言(泛型,Lambda)
类库(集合,并发,网络,IO/NIO)
JRE(Java运行环境,JVM,类库)
JDK(Java开发工具,包括JRE,javac,诊断工具)


Java是解析运行吗?
不正确!
1,Java源代码经过Javac编译成.class文件
2,.class文件经JVM解析或编译运行。
(1)解析:.class文件经过JVM内嵌的解析器解析执行。
(2)编译:存在JIT编译器(Just In Time Compile 即时编译器)把经常运行的代码作为"热点代码"编译与本地平台相关的机器码,并进行各种层次的优化。

(3)AOT编译器: Java 9提供的直接将所有代码编译成机器码执行。



猜你喜欢

转载自blog.csdn.net/echo6_y/article/details/80725105