清华大神解密JVM与Class文件格式,全面而透彻的教程来了

前言:

清华大佬终于把JVM入门以及Class格式的知识讲解透彻了!这份教程是全面而透彻的,将为你揭开JVM和Class文件格式的神秘面纱。不论你是初学者还是有一定经验的开发者,这个教程都能帮助你深入理解JVM的工作原理和Class文件的结构。你将学习到JVM内存管理、类加载机制、字节码解析等核心知识。更值得一提的是,这个教程是由清华大佬亲自讲解,保证了内容的权威性和可靠性。立即开始你的JVM与Class文件格式的探索之旅吧!

JVM入门以及Class文件格式

这是java虚拟机中的内容,分为下面这个几个大类,内容还会更新。小编今天给大家分享前两个内容,第一个和第二全部分享完。

  • 1:虚拟机的基础概念

  • 2:class文件结构

  • 3:内存加载过程

  • 4:运行时内存结构

  • 5:JVM常用指令

  • 6:GC与调优(重点)

我们首先来看第一章的内容叫jvm的基础入门。java是怎么样从编码到执行的整个的过程,到底什么是 jvm。我们有一个文件x.java->执行javac->变成x.class,当我们调用Java命令的时候class会被装载到内 存叫classLoader。一般的情况下我们写自己类文件的时候也会用到java的类库,所以它要把java类库相 关类也装载到内存里,装载完成之后会调用字节码解释器或者是即时编译器来进行解释或编译,编译完 之后由执行引擎开始执行,执行引擎下面面对就是操作系统的硬件了。这块的内容叫jvm。下图是大体的 流程,大家要存到脑子里。java编译好了之后变成class,class会被加载到内存与此同时像String、 Object这些class也会加载到内存。

咱们原来老师会问一个问题,说:java是解释执行的还是编译执行啊,其实解释和编译是可以混合的, 特别常用的一些代码,代码用到的次数特别多,这时候它会把一个即时的编译做成一个本地的编译,就 像C语言在windows上执行的时候把它编译成exe一样,那么下次再执行这段代码的时候就不需要解释 器来一句一句的解释来执行,执行引擎可以直接交给操作系统去让他调用,这个效率会高很多。不是所 有的代码都会被JIT进行及时编译的。如果是这样的话,整个java就变成了不能跨平台了,有一些特定 的,执行次数好多好多的时候,会进行及时编译器的编译,这一块叫java虚拟机。

JVM现在我们可以称之为它是一个跨语言的平台,java叫跨平台的语言,这个大家都了解了,作为JVM 虚拟机来讲目前能够在jvm上跑的引言特别多,除了java以外,还有scala,kotlin,groovy,clojure, jython,jruby等等,据调查说是有一百多种了,也就是说有一百多种语言是直接可以跑在虚拟机上 的,当然所谓的jvm虚拟机本身也是一种规范,Linux上有Linux的实现,unix上有unix的实现.... Java Virtual Machine帮你屏蔽了操作系统的这些底层。

  • jvm与java无关

java虚拟机怎么才能做到这么多语言都可以往上跑呢,关键的原因就是class这个东西,任何语言只要你 能编译成class,符合class文件的规范你就可以扔在java虚拟机上去执行。所以,从jvm的角度来讲,它 是不看你任何的语言的,只和class文件有关系,不管你是谁,只要你变成class,那就是我的菜,关于 这一点我相信大家应该问题不大。

  • jvm是一种规范,他就定义了java虚拟机应该能够执行什么等等... java虚拟机应该具备哪些模块, 遇到什么样的指令应该做一些什么样的东西。关于这个网站是怎么定义的,大家可以找到Oracle 的网站去看,每个版本和每个版本都不一样,网址给大家写在下面。

-java virtual machine specifications -https://docs.oracle.com/en/java/javase/13/ -https://docs.oracle.com/javase/specs/index.html

Java SE13/12/11/10/9/8你自己随便看,在这我下载了一份java SE13的。这里面说了两个内容:

  • 1、Java Language Specification java语言的规范,java语言中哪些语法能用哪些语法不能用都在 这里。java SE13里面它增加了哪些新内容啊在哪儿看呢?Preview features:Switch expression and Text blocks

  • 2、今天我们不是讲java语言13里面有什么新内容,要讲的是Java Virtual Machine Specification。这篇文档才是将来你要直接阅读的。你要单独去读呢应该是有600多页,比较费 劲,这不耽误你下载下来用到的时候再去查。

jvm是虚构出来的一台计算机,既然它是一个虚拟的计算机,你就可以想象成一层单独的机器,那 它有自己的CPU,有自己的指令集,汇编语言。我们后面会讲java的汇编语言。它是一台虚拟的机 器,相当于自己是一个操作系统,自己的这个操作系统是怎么管理的,我们后面会讲。

  • 虚构出来的一太计算机

字节码指令集(汇编语言) 内存管理:栈 堆 方法区等

在讲整个虚拟机的过程中我们唯一不会讲的是java怎么编译的过程,这里面是编译原理的过程。大家看 我朋友圈有一个想法是要做一个能够跑在JVM上的语言,既然说任何语言,你只要翻译成class文件就可 以,其实你们可以自己想象一下,我要设计一个语言,然后我再写一个程序,能够把它翻译成class文 件,这个语言就可以跑在JVM上。我这么讲,大家理解吧,我现在正在给这个语言起名字,这个语言的 目标是什么呢?就是给小孩儿用的,现在呢,国家提倡从小开始培养这种编程和逻辑能力,然后我们想 设计一门中文的,小孩们聊起来的时候不是聊英文而是聊中文这样的一种语言,然后呢,我们会把它翻 译成class在java虚拟机上去执行,这个语言现在正在起名字,如果大家有什么想法儿的话可以告诉我 们。

常见的JVM的实现

我们来聊一聊最新jvm的实现,刚才咱们说了jvm是一种规范,既然是一种规范他就有具体的实现,定 义了一个接口,具体的实现类也特别多,其实都是一样的。三流的企业做产品、二流的企业做服务、一 流企业定标准。这就是定的标准,Oracle定了这一个java虚拟机的实现标准。他自己也有一些实现,当 然也是从SUN收购过来的。

  • Hotspot : 目前我们用的最多的就是java虚拟机,它是Hotspot。在命令行里写:java -version。它 会输出你现在用的虚拟机的名字,执行模式,版本等信息。64位的 Server版 用的执行模式是 mixed mode

  • Jrockit : 其实除了oracle之后还有很多很多的实现,原来比较有名的BEA是三个创始人的首字母的 缩写形成的,这家公司有自己的虚拟机的实现叫Jrockit 曾经号称世界上最快的JVM,后来被Oracle 收购,合并于hotspot

  • J9 -IBM : IBM有自己的java虚拟机的实现,他的名字叫J9

  • Microsoft VM : 微软有自己的实现,叫Microsoft VM,不管怎样,这些都是符合虚拟机规范的。

  • TaobaoVM :当然也只有这种体量、一定规模的厂商才会开发自己的虚拟机,比如说淘宝有自己 的VM,它实际上是hotsopt的定制版,专门为淘宝准备的,阿里、天猫都是用的这款虚拟机。

  • LiquidVM : 是一个直接针对硬件的虚拟机VM,它下面是没有操作系统的,不是Windows也不是 Linux,下面直接就是硬件,效率运行起来就更高了。

  • azul zing : 这家公司是非常牛的azul他有一个产品叫zing,这是一个商业产品,是一个土豪才用 的起的,很贵。既然这样就一定有自己的特点:快、非常快,尤其是垃圾回收在1毫秒之内,是业 界标杆。他的一个垃圾回收的算法后来被Hotpot吸收才有了现在的ZGC 。

关于Java收费

前一阵子java收费搞得沸沸扬扬,我还专门录了一段视频叫:java要收钱,我该怎么办? 如果你想了解 来龙去脉去网上搜一下我的视频。 中心思想很简单hotsopt8开始不在提供那种免费升级了,谁要想8的 升级是要掏钱的说的是虚拟机收费而不是Java语言收费。java语言要是收费java语言就完蛋了。是我自 己hotsopt虚拟机它要收费,oracle说我不再想免费的给你用了,免费的升级免费的做维护。麻烦你以 后想要升级版本需要向我交钱,所以8以后都要向我交钱。但是你不用它不就完了吗,你可以用Open JDK嘛hotsopt开源版本或者是TaobaoVM。

JDK、JRE、JVM

好的,因为有的同学水平参差不齐我需要给大家解释一些相应的概念,JDK-JRE-JVM到底是一个什么样 的关系,下面这张图一看应该你就能看明白,JVM叫java的虚拟机只是来执行的,就是你所有的东西都 弄好了之后它来执行;JRE运行时环境,java要想在操作系统上运行,除了虚拟机之外,java的那些核心 类库你得有,如果那些核心类库没有的话你跑不起来;JDK是java开发工具包,包含了JRE和JVM。

Class File Format

同学们我们继续,来讲第二章的内容。刚刚你看到的是整个的java虚拟机是以class文件为核心,这 class文件是什么,我们今天来分析一下。咱们同学面试的时候很少有人会面到这些问题,因此大家学这 个东西你要当成一个兴趣去学,我本人是非常有兴趣的。是对你自己内力提升的一个过程。

整个class文件的格式就是一个二进制字节流,这个二进制字节流是由java虚拟机来解释的。

大家来看这个最简单的小程序,不用再看里面已经没有什么东西了。我们要讲的是这个东西编译完后会 是一个class文件

package com.mashibing.jvm.bytecode; public class T0100_ByteCode01{ }

我们看编译完后,再看反编译版本就已经有区别了。它会自动的帮你加了构造方法默认的无参构造,其 实任何文件打开里面全都是0101,我这么说大家应该没有任何意见,不管你是png、jpg、txt、avi也好 打开之后内部全是0101。

这个class文件如果你用16进制的编辑器来打开之后看里面的内容是这么一个东西如下图。 这个工具 叫sublime

打开文件,这个工具有一个好处在下图我红框圈起来的地方可以选择8机制、10进制、16进制、2进 制。

ClassFileFormat

整个class文件的格式就是个二进制的字节流,这个二进制字节流怎么解释那就看由谁来解释了,这个东 西是由java虚拟机来解释的,它是怎么来解释的呢ClassFileFormat大概是有这么几种内容我给大家画了 一个图,因为很多书上文章里讲这部分内容用的都是表格,用表格的话你要想从脑子里有一个从大到小 的概念是比较难的,所以我给大家画了一张图,这张图从大到小看完之后你这个class文件你八九不离十 就搞定了。

整个class里面有这么几种内容如下图

把这些东西呢给他记下来或者能用笔在纸上画下来,这个要求有点高,感兴趣可以研究,实在记不住也 就算了。下面我尝试在PPT上给大家解释一下。

下图这里可以很清楚的看出每部分有多长,一般u1,u2,u3...u8,u指的是无符号整数,u1就是一个字节, 把这一个字节看成无符号整数,u1就是一个字节的意思,u2俩个字节,u4四个字节,u8八个字节。一 个小格是一个i字节,对16进制来说,一个16进制就是四位,两个16进制就是一个字节。前面的四个字 节,指的是这个文件的统一标识符,当我们看到这个文件的统一标识符的时候,就知道它是class文件。 很多文件都是这样来标识的,它们都有自己的头,用16进制打开,前几位一般都一样。看到 CA FE BA BE 这就是java编译完的class文件,四个字节。这部分叫做magic Number,魔术。

00 00是minor version,minor version表示的是整个版本的小标识符,00 34是major version。 我们 看到的class文件的时候,这八个字节代表的就是这个意思(强调:这个里面写的是16进制)。

00 10 constant_pool_count是常量池里面有多少个内容,常量池是class文件里最复杂的内容,而且常 量池里会互相引用,以及常量池会被其他的各方面引用,所以常量池是极其复杂的。能存多少常量: constant_pool_count-1,常量池是从1开始的,数组是从0开始,所以要减去1.从1开始的原因是:它有 一个0存在于那里,将来没准哪天有些引用指向,表示不指向任何常量池的一项,那时候就可以用0来表 示,保留了一个可能性。

有很多可以观察ByteCode的方法:

  • 1:javap - java自带的叫javap的命令

  • 2:JBE - 他除了可以观察二进制码之外还可以直接修改

  • 3:JClassLib - IDEA插件之一,这个是我最常用的

这个插件用起来很简单,当你安装完这个插件后就会有这个选项了->show Bytecode With jclasslib 他分析的非常多:

->General Information通用的一些信息,前面图解也有说明这些信息的代表意思。

->ConstantPool 常量池里面的常量类型特别多,总而言之常量池是一个class里面最复杂的东西。

我们来看一眼这个源文件吧,对我们学习的人来说,它真的不难,只是比较繁琐。因为任何一个地方都 需要去查,这个代表什么,另一个指向哪里。但真正设计的人是比较牛叉的,class文件设计的特别紧 密,紧致,没有任何的分割符。因此这个class文件也得到了很多人的认可,所以以后大家伙设计编程语 言的时候,都不要设计格式了,我们只要把它设计成class文件就可以了。

分析一个,比如:第一行最后两位07,我们去查 7 CONSTANT_Class_info,再去看Constant Pool中的 2号是一个CONSTANT_Class_info然后他的CONSTANT_Class_info又指向了我们当前自己类的名字它指 向了14号。然后你再看二进制是不是指向了14号啊?07是我们常量池第二号的标记,接下来000e就是 14啊。

你说学这个东西有什么用,这就像你学古诗一样,学完古诗有什么用吗,提升你审美的一种感觉,提升 你的内力,在你的公司里面装X用,面试不会问这个,但是在你的简历写上说对class文件有过深入研 究,了解class文件的详细信息,面试官看到这些信息就会和其他的面试者区分开来。

->Interfaces:我们没有实现它所以无所谓 ->Fields:由于我们这个class没有任何的属性,所以fields里面也没有任何东西 ->Methods:它会给我们构造方法加一个无参的构造方法

一个方法的汇编实现翻译完了之后全都是下图这些东西,这些东西就是java的汇编,当作为一个java虚 拟机来讲当它读到一个class文件里面内容的时候他就要去查表里代表的是哪条指令

其实这方法还有附加属性,最主要的是Code,就是这个方法的代码是怎么实现的。这个方法的具体的 实现才是最重要的,当我们看到这个方法的时候我们回去里面找它的一条一条的指令。

在Java虚拟机规范里面第七节,整个的二进制码分别代表的什么内容,这个方法的具体实现翻译成Class 之后全是这些东西,这些东西就是java的汇编,所以当我们java虚拟机来讲当它读到一个class文件里面 内容的时候,就是找到这个方法的一个实现的时候,例如读到了 30 ,它就要去表里面查30代表的是哪 一条指令,然后在把这条指令翻译过来它到底是哪条指令 ->aload_0,然后再去表里面查aload_0里面 到底是个什么东西。

​aload_0汇编指令代表的是把本地变量表的第0项放到栈里,放到栈里之后进行第二条指令 invokespecial,一环套一环,这就是jvm汇编语言.

我们来回顾一下,整个class 文件有好多种类型,当我们理解一些基础的内容之后呢再来看那些就没有 那么头疼了,它是一环套一环的,整个class文件有这么几个:

  • Magic Number

  • Minor Version(小号)/Major Version(主号)

  • constant_pool_cont(有多少个常量池)

  • 常量池-1具体的内容有很多种类型

  • access_flags(指的是整个class你前面写的是public还是privote等什么东西)

  • this_class(我当前的这个类是谁

  • super_class(父类是谁)

  • Interfaces_count(实现了哪些接口)

  • Interfaces(接口的索引)

  • fields(有哪些属性)

access_flags :是不是public的,是不是static的,是不是final的??? name_index:名称的索引 descriptor_index:描述符,到底是什么类型的 attributes:另外它所附加的一些属性,有的有,有的没有

methods(方法的各种结构,到底是怎么样进行标识的,它名字的索引、描述符的索引、附加属性) attributes(附加属性里面最重要的一项是方法表,也就是这个方法编译完成之后的字节码指令,jvm看 到这个指令的时候首先会读一些指令进来,然后根据指令去查自己的指令表,找到执行之后再来看你这 个指令到底是什么意思)

用这个classLib是在这里看,它会给你放在General Information里面

附加属性里面最重要的一项是方法表,也就是这个方法编译完成之后的字节码指令,那么jvm看到这个 指令的时候首先会读这个指令进来,然后根据这个指令去查指令表,拿aload_0来说,在方法的局部变 量表里面的第0项,只要不是静态方法它永远都是this,放到栈里之后进行第二条指令invokespecial特 殊调用this的构造方法,然后jvm在根据指令一条一条的执行,当我们看到这个Code的时候,最后一条 指令是return。

我们看到的是aload_0,aload_0是2a,然后是b7,b7对应的是invokespeciaal。所以对于java虚拟机来 说它读一条指令,执行这个方法的时候,读了一条这个指令。它一查aload_0,然后做向下操作。接下 来在读下一条指令,一查是b7,做下一个操作。invokespeciaal应该是有参数的,带了俩个参数00 01。他们是指向常量池第一号的,所以它调用了java long的构造方法。干了这么个事。下一条指令是 b1,是return,说明方法结束了。因此构造方法里面这5个字节。是谁那?是我们这个文件的构造方法 的具体实现。 刚刚你看到了生成了一个方法,是构造方法。这方法有一个Code属性,Code属性里面是 真真正正这个方法的实现,这个方法站在虚拟机的的角度它是怎么实现的呢,它就是这5个字节来具体 实现的,在我们看来这个方法里面什么也没写,在调用这个方法的时候,你需要调用Object的构造方法 这点没问题吧。我们任何的一个class,你不给它写任何构造方法时候,它会自己生成一个构造方法 。 而生成的这个构造方法里面不做任何调用的时候,他会调用父类的构造方法 Objeck 。

今天带大家入门了class的文件格式,但是我并没有详细的解释这里面每一个字节都代表了什么,如果大 家非常感兴趣请大家下去之后你去对照我给大家总结出来的这个xmind文档你就能查出来每个字节代表 的是什么东西了。

一定要从简单往复杂一点一点来,等你加了方法之后再来看它里面的二进制码到底包含了哪些东西,一 步一步的class文件你就全部都熟悉了,方法牵扯的内容太多,我们放到下篇讲。

PS:如果有需要完整版的小伙伴们,可以点击下方传送门,即可免费获取!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值