杨晓峰-java核心技术36讲(学习笔记)- 第1讲 | 谈谈你对Java平台的理解?

杨晓峰-java核心技术36讲(学习笔记)

接下来我会分享杨晓峰-java核心技术36讲的学习笔记,内容较多,补充了其中一些牛人评论,相对详细(仅供个人学习记录整理,希望大家支持正版:https://time.geekbang.org/column/intro/100006701)

第1讲 | 谈谈你对Java平台的理解?

谈谈你对Java平台的理解?“Java是解释执行”,这句话正确吗?

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

我们日常会接触到JRE(Java Runtime Environment)或者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语言特性,包括泛型、Lambda等语言特性;基础类库,包括集合、IO/NIO、网络、并发、安全等基础类库。对于我们日常工作应用较多的类库,面试前可以系统化总结一下,有助于临场发挥。

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

当然还有JDK包含哪些工具或者Java领域内其他工具等,如编译器、运行时环境、安全工具、诊断和监控工具等。这些基本工具是日常工作效率的保证,对于我们工作在其他语言平台上,同样有所帮助,很多都是触类旁通的。
下图是我总结的一个相对宽泛的蓝图供你参考。

image-20210601232335762

众所周知,我们通常把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编译器优化方式,比如分支预测,如果不进行profling,往往并不能进行有效优化。

除了我们日常最常见的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虚拟机基本原理和相关工具,希望对你有所帮助

讨论区

“一次编译、到处运行”说的是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这一即时编译方式,可以将字节码直接转化成高性能的本地机器码,这同样 是虚拟机的一个构成部分。


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提供的直接将所有代码编译成机器码执行。
关注了好久,终于期盼到了第一讲。
在看到这个题目时,我并没有立马点进来看原文,而是给了自己一些时间进行思考。
首先,个人觉得这个题目非常的抽象和笼统,这个问题没有标准答案,但是有『好』答案,而答案的好坏,完全取决于面试者自身的技术素养和对Java系统性的了解。我的理解如下:

宏观角度:
跟c/c++最大的不同点在于,c/c++编程是面向操作系统的,需要开发者极大地关心不同操作系统之间的差异性;而Java平台通过虚拟机屏蔽了操作系统的底层细节,使得开发者无需过多地关心不同操作系统之间的差异性。
通过增加一个间接的中间层来进行”解耦“是计算机领域非常常用的一种”艺术手法“,虚拟机是这样,操作系统是这样,HTTP也是这样。
Java平台已经形成了一个生态系统,在这个生态系统中,有着诸多的研究领域和应用领域:
1. 虚拟机、编译技术的研究(例如:GC优化、JIT、AOT等):对效率的追求是人类的另一个天性之一
2. Java语言本身的优化
3. 大数据处理
4. Java并发编程
5. 客户端开发(例如:Android平台)
6. ......

微观角度:
Java平台中有两大核心:
1. Java语言本身、JDK中所提供的核心类库和相关工具
2. Java虚拟机以及其他包含的GC
1. Java语言本身、JDK中所提供的核心类库和相关工具
从事Java平台的开发,掌握Java语言、核心类库以及相关工具是必须的,我觉得这是基础中的基础。
>> 对语言本身的了解,需要开发者非常熟悉语言的语法结构;而Java又是一种面对对象的语言,这又需要开发者深入了解面对对象的设计理念;
>> Java核心类库包含集合类、线程相关类、IO、NIO、J.U.C并发包等;
>> JDK提供的工具包含:基本的编译工具、虚拟机性能检测相关工具等。
2. Java虚拟机
Java语言具有跨平台的特性,也正是因为虚拟机的存在。Java源文件被编译成字节码,被虚拟机加载后执行。这里隐含的意思有两层:
1)大部分情况下,编程者只需要关心Java语言本身,而无需特意关心底层细节。包括对内存的分配和回收,也全权交给了GC。
2)对于虚拟机而言,只要是符合规范的字节码,它们都能被加载执行,当然,能正常运行的程序光满足这点是不行的,程序本身需要保证在运行时不出现异常。所
以,Scala、Kotlin、Jython等语言也可以跑在虚拟机上。
围绕虚拟机的效率问题展开,将涉及到一些优化技术,例如:JIT、AOT。因为如果虚拟机加载字节码后,完全进行解释执行,这势必会影响执行效率。所以,对于这个运行环节,虚拟机会进行一些优化处理,例如JIT技术,会将某些运行特别频繁的代码编译成机器码。而AOT技术,是在运行前,通过工具直接将字节码转换为机器码。
1,JVM的内存模型,堆、栈、方法区;字节码的跨平台性;对象在JVM中的强引用,弱引用,软引用,虚引用,是否可用fnalise方法救救它?;双亲委派进行类加载,什么是双亲呢?双亲就是多亲,一份文档由我加载,然后你也加载,这份文档在JVM中是一样的吗?;多态思想是Java需要最核心的概念,也是面向对象的行为的一个最好诠释;理解方法重载与重写在内存中的执行流程,怎么定位到这个具体方法的。
2,发展流程,JDK5(重写bug),JDK6(商用最稳定版),JDK7(switch的字符串支持),JDK8(函数式编程),一直在发展进化。
3,理解祖先类Object,它的行为是怎样与现实生活连接起来的。
4,理解23种设计模式,因为它是道与术的结合体。
1. 一次编译,到处运行。jvm 层面封装了系统API,提供不同系统一致的调用行为。减少了为适配不同操作系统,不同架构的带来的工作量。
2. 垃圾回收,降低了开发过程中需要注意内存回收的难度。降低内存泄露出现的概率。虽然也带来了一些额外开销,但是足以弥补带来的好处。合理的分代策略,提高了内存使用率。
3. jit 与其他编译语言相比,降低了编译时间,因为大部分代码是运行时编译,避免了冷代码在编译时也参与编译的问题。
提高了代码的执行效率,之前项目中使用过 lua 进行相关开发。由于 lua 是解释性语言,并配合使用了 lua-jit。开发过程中遇到,如果编写的 lua 代码是 jit 所不支持的会导致代码性能与可编译的相比十分低下。
可以把Java程序设计语言、Java虚拟机、Java API类库及相关工具,这三部分统称为JDK,JDK是用于支持Java程序开发的最小环境;可以把Java API类库中的Java SE API子集和Java虚拟
机这两部分统称为JRE,JRE是支持Java程序运行的标准环境。

提起Java,必然会想起TA跨平台的特性,但是跨平台重要吗?重要!因为可以write once,run anywhere,这是程序员的终极梦想之一。但是跨平台重要吗?不重要!作为程序语言,会更加关注TA的生态、兼容性、安全性、稳定性,以及语言自身的与时俱进。要要理解Java平台,JVM是必须要迈过去的坎,将会看到另外的风景。

为什么我们就不能把JVM作为透明的存在呢?
勿在浮沙筑高台,以JVM的GC为例。既然Java等诸多高级程序语言都已经实现了自动化内存管理,那我们为什么还要去理解内存管理了?因为当我们需要排查各种内存溢出、泄漏等底层问题时,当垃圾收集成为我们开发的软件系统达到更高并发量、更高性能的瓶颈时,我们就需要对这些“自动化”技术实施必要的监控与调节优化。
任何软件问题都可以通过加一层来解决:
有了系统API就屏蔽了不同硬件的区别,
有了编译器就屏蔽了不同机器语言的区别,
有了JVM就屏蔽了不同操作系统的区别,
有了TCP/IP就屏蔽了不同系统之间通讯的差异,
有了语音识别和翻译就屏蔽了不同语言的差异。
也许有一天人工智能可以直接把自然语言翻译成机器码直接生产可用的软件。
Java平台包括java语言,class文件结构,jvm,api类库,第三方库,各种编译、监控和诊断工具等。
Java语言是一种面向对象的高级语言;通过平台中立的class文件格式和屏蔽底层硬件差异的jvm实现‘一次编写,到处运行’;
通过‘垃圾收集器’管理内存的分配和回收。
jvm通过使用class文件这种中间表示和具体语言解耦,使得任何在源码早期编译过程中以class文件为中间表示或者
能够转换成class文件的具体语言,都能运行jvm之上,也就可以使用jvm的各种特性。
api类库主要包含集合、IO/NIO、网络、并发等。
第三方库包括各种商业机构和开源社区的java库,如spring、mybatis等。
各种工具如javac、jconsole、jmap、jstack等。
编译型语言:C/C++、 Pascal(Delphi)
编译就是把源代码(高级语言,人类容易读,容易理解)转换成机器码(CPU能理解,能高效的执行)
解释型语言:JavaScript、Perl、Python、Ruby
解释就简单多了,解析源代码,并且直接执行,没有编译过程
编译程序是整体编译完了,再一次性执行。 而解释程序是一边解释,一边执行
JAVA语言是一种编译型-解释型语言,同时具备编译特性和解释特性
其所谓的编译过程只是将.java文件编程成平台无关的字节码.class文件,
并不是向C一样编译成可执行的机器语言,在此请读者注意Java中所谓的“编译”和传统的“编译”的区别。
作为编译型语言,JAVA程序要被统一编译成字节码文件——文件后缀是class。此种文件在java中又称为类文件。
java类文件不能再计算机上直接执行,它需要被java虚拟机翻译成本地的机器码后才能执行,而java虚拟机的翻译过程则是解释性的。
java字节码文件首先被加载到计算机内存中,然后读出一条指令,翻译一条指令,执行一条指令,该过程被称为java语言的解释执行,是由java虚拟机完成的。
以上说的是Java的解释执行,但是比如我们大多数情况使用的Hotspot JVM,都提供了动态编译器编译器JIT,能够追踪热点代码, 然后变成机器指令,这种情况下部分热点代码就属于编译执
行,而不是解释执行了
其实甭管它什么解释还是编译, 了解了底层的原理就行了
看了几个留言,发现点问题。首先C/C十十目前也是支持动态编译,只不过是编译成DLL库。如果不在集成环境下编译Java程序,你会发现Javac编译出的。cIass文件类似。O文件。
Java 平台不会强制您时刻关注内存分配(或使用第三方库来完成此工作),它提供了开箱即用的内存管理功能。当您的 Java 应用程序在运行时创建一个对象实例时,JVM 会自动从堆 中为该 对象分配内存空间— 堆是一个专门留给您的程序使用的内存池。Java 垃圾收集器 在后台运行,跟踪记录应用程序不再需要哪些对象并从它们回收内存。这种内存处理方法称为隐式内存管理, 因为它不需要您编写任何内存处理代码。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值