00:00
好,下面啊,咱们来讲一下这个方法区的这个内部结构啊,这呢也是我们认为稍微对于方法区来讲呢,是比较重要的一个事儿啊,就是方法区里边啊,到底都存什么信息对吧?诶我们先来看这样一个简图,那我们呢,这个写的是Java源程序,点Java结尾的这个源程序啊,经过编译以后,诶,咱们得到呢,称为叫自解码文件,那自解码码文件呢,我们通过使用叫类的加载器,把它呢,诶加载到咱们的运行时数据区。那么相应的针对于自金码文件当中这个数据啊,那我们就会有一个具体的分配,那针对于我们说的这个类信息本身,呃,咱们呢,需要给它存放在这个叫方法区,诶存放到这个方法区里边,那真正我们这个方这个这个最起码文件对应的这个类呢,要执行的时候呢,我们相应的呢,还需要呢,比如说扭对象了,那就在堆空间中去扭对象,那对应的我们在这个呃执行的过程当中,肯定都是方法的一些调用了,那这时候我们必然的也会在这个虚拟站当中啊,去分配相应的一个一个战争代表呢,是一个一个方法的调用,那在整个执行过程当中,我们也要用到这个程序计数器,那记录呢,我们整个呢,先后执行的每一个线程当中啊,你这个代码呢,到底执行到哪一行了是吧?来来有一个这个计数,哎,就是我们这个相应指令的一个地址,OK,在这个成熟记程序计数器里边呢,进行一个记录行,那么我们现在呢,主要关心的是这个方法区,这个方法区的话呢,我这只是这个一个概图啊,就是这个方法区里边到底放什么呢。
01:29
主要在方法系当中存放的就是我们说叫类信息,当然了,这个叫类呢,是一个概述啊,你可以理解成是叫class,那其实呢,对于我们说的叫innu,就是枚举类啊,注解啊,接口啊等等,哎,这呢我们也统称为呢叫做类型类信息,或者呢我们为代表叫类型信息也可以啊,那除了这个类信息或者叫类型信息之外呢,我们另外一个非常重要的信息呢,叫做运行时常量值,这呢我下边又写了个叫字符串常量,这个呢我加了一个红线啊,这呢就是在不同的这个GDK版本当中,关于这个磁库串常量值存放的位置啊,会有一些变化啊,这个大家稍微关注一下这个事情,这呢只是一个呃,简要的一个图,然后呢,我们看这块啊,相对来说比较详细一些,在这个深入理解扎化虚尼这本书当中,对方法区的存储内容啊,做了如下的一个描述啊,这块呢大家可以记一下,说呢,我们在方法区里边主要都存储什么信息啊,哎,这块提到叫类型信息。
02:26
啊叫类型信息呢,是比较准确的,因为呢,我们不光存放的是类对吧?啊像接口啊,枚举啊,这个注解啊等等这呢也算是啊我们这块叫类型啊,所以叫类型信息,然后呢常量,哎常量呢,因为是运行的时候呢,加载过来的啊主要呢对应的我们称为呢叫运行时常量值啊,以及呢叫静态变量和即时编译器编译以后的这个代码缓存,这个即时编译器呢,就是我们说的GI,这个咱们到后边讲到哎这个内容的时候,执行引擎的时候呢,我们会讲这个叫git,到时候呢,我们再说一下这个代码缓存的问题啊行,主要呢我们存放的是这个信息啊,当然你也会看到说我下边写的好像跟上面呢有点不对应是吧,我下边写的时候呢,是不是还放了这个叫预信息和这个方法信息,哎,那关于预信息方法信息呢,大家也可以看到呢,就是哎涵盖在我们这个类型信息当中的,哎,这也是可以的。
03:17
行这呢,就是我们说的这个方法区啊,到底哎存放些什么信息,什么内容,就是这个意思。那这块呢,一方面大家记一记,另外一方面啊,也不要呃给他死记硬背,什么意思啊,就是这呢,是咱们通常所认为的呢,存放的一个内容,但是呢,随着这个JDK版本的更新,咱们Java虚拟规范呢,也做了一些调整,像这个比如说静态变量啊,比如说运行时常量池中的一个s table啊,字符串常量池它们的存放位置啊,实际上呢,会有一些变化。这个在咱们下一节当中,咱给大家说这个具体的一些演进细节是什么。啊,就好比是什么呀,咱们这块说的这个版本呢,有点像是一个,嗯叫什么呀,比较呃标准的或者叫经典的,对,用经典这个词呢,我觉得比较合适啊,经典歌曲是吧,经典曲目,经典的几个电影是吧,就是经典呢,首先呢,它这个通常呢,时间都不会特别短了,你要新出的这个不能说要经典的,一般呢都会有一些年头,对吧?那其次的话呢,就是嗯,它可能是比较规范一些,或者那是我们通常所说的一种情况,那后续的话呢,可能会有一些变化。
04:26
嗯,就是这样的一个情况,好,那我们这块呢,就举个例子啊,比如说呢,咱们提到的叫古这个四大文明古国是吧。那这个我就简写了,四大文明古国,这个大家呢,都知道是哪吧。古埃及啊,古巴比伦,古印度,古中国是吧?这呢是我们通常所说的叫四大文明古国,那也可以理解成呢,是经典的这个四大国,那现在来看的话呢,四大文明古我们说呢,像古代埃及,古代巴比伦和古代印度呢,都算是文化有断层了,那只有中国的话呢,这个象形文字咱们呢,是一直这个文化呢,是延续下来的,就是还是延续了这个古中国的这样一些传统啊,一些文化就是没有出现这个叫文化的一个断层。
05:09
啊,那有点类似于我们这块,你要说全的话呢,有这样的一些部分,但是呢,细节来说,现在的话呢,我们里边有一些结构呢,是有变化的,那具体的变化是什么,咱们下一节再说啊大家呢,先关注一下我们这几个信息,好,那下面咱们就一个一个呢来给大家解释一下,那关于这个类型信息啊,类的话,类型的话我们说可能是类,也可能是接口,可能枚举类,可能是注解,对吧?哎,它会存储着我们这些类型当中的,比如说你的一个呃,全类名啊是吧,全类名是什么样子的啊,以及呢,说你的直接负类是什么,你都实现了哪些接口啊,当然这里边呢,我们说对于接口和这个object来讲呢,他们就没有负类。那这个应该很清楚,这个类型它的修饰符是什么啊,以及呢,你这个实现了一个接口,因为呢,我们这个类呢,实现接口可以有多个嘛,所以它是一个列表,那同时这个列表呢,还是有序的,也就是说我们比如说这是一个类,哎,或者我们这直接就看这个代码,咱们这呢有个类,这个类呢,它实现了两个接口,或者呢实现两接口,那这两个接口呢,它也也是有顺序的,这个就放在这个角标为零的位置,这个呢是角标为一的位置啊这要注意行,这是我们说的这个类型信息,那么关于这个叫域信息。
06:20
就是咱们平时呢,所说的叫乘以变量。啊,这个有时候也翻译成属性,其实准确的说呢,我们这个field呢,翻译成叫域呢,更合适一些啊,因为比较早呢,大家都当成叫属性了哈,所以说呢,有时候我们就老是说属性,属性其实呢,我们准确的讲呢,应该叫field,那翻译过来呢,叫做欲。啊叫做域,那在我们这个方法区里边存出咱们这个类型信息的时候啊,他也会把我们这个域的信息呢,也会完整的保存下来,包括什么呀,包括我们这个玉的名称啊,玉的类型,它的修饰符等等,修饰符呢,有这样一些,从这里边呢,选这个具体的一个或几个啊,就是成为某一个自己嘛。
07:01
还有呢,包括这个叫方法的信息本身的方法,我们说声明的话呢,就比较复杂,这呢也会保存,比如方法的名称啊,反之类型啊,当然你是word也行,咱把Y呢,其实也可以看成是一种类型。是这样子的啊,包括呢,咱们这个word.class那其实也对应的是一个大的class的实例,嗯,还比如说咱们这个方法的这个参数,参数的个数类型啊,这呢都包含了,包括方法的一个修饰符啊,以及呢,这个方法的这个实体,就是所谓的方法体里边,那涉及到我们这个字解码你的这个操作入站啊,局部变量表啊,还有我们这个行参的一个大小啊,诶等等都有啊,一会儿咱们能看到,包括呢,如果这个方法呢,有异常,这还有一个呢,叫exception table啊,就是异常表,记录了异常表的这样的一些信息。哎,我这样说的话呢,大家可能会觉得有点干是吧?啊有点干,那咱们呢,给大家举个例子啊。好,来看这这个代码的话呢,大家其实拿任何一个类呢,都能说明问题,只不过呢,这块呢,我相对呢,举的是一个比较有代表性的,那所谓的代表性呢,就是我们让这个信息啊展示的更加完整一些,比如呢,这个类呢,我们继承了一个副类,实现了两个接口属性的话呢,有这个静态的非静态的,有权限大的,有权限小的,对吧?然后方法这块呢,我刻意的构造器没有写,我刻意的构造器没有写,大家注意一下,那么我们说呢,任何一个类呢,都有构造器没有写,是不是提供一个默认空参的构造器啊。
08:28
一会我们看一下这个最节码文件,咱们要是反编译以后,你看看这个构造器是不是有啊,然后呢,这个方法我们这定义了一个普通的实例方法,还有一个呢,静态方法,这上有参数,还有返回值,就是尽可能诶而且我们这还有异常是吧,尽可能这块呢,我就希望呢,能够看到不同场景的这个这个这个信息是吧?好,那这个呢,是我们当前的这个类的声明,声明完以后呢,咱们此时呢做一个啊re compel做一个编译。
09:02
编译稍微有点慢是吧,那编译完以后的话呢,咱们就可以呢,针对这个自解码文件啊,这个咱们默认的是生成到我这个al这个目录下啊,找到这个九里边。在这对吧,这个呢叫method的,嗯,Inner structure,哎在这啊,找到这个资询文件以后啊,咱们可以通过两种方式呢去查看。诶,两种方式去查看这个当然了,这个本身这个文件本身咱CTRLC一下放到桌面上,当然了,要这时候呢,双击打开。嗯,就是大家呢,要双击打开,有可能使用的是这个,诶是不是叫ID的plus可能是打开的是吧。诶,比如有可能你是用这个类似的这个记值,本来打开这个呢,打开通常就不理想了,因为这里边呢,咱们会有一些这个特殊的一些字符,你得用十六十六进制的这个格式来打开才行,哎,咱这呢就用它开不合适,我这呢是因为提前装了这个工具了啊,一个呢是接class LA,另外呢是这个bary viewer啊这个用谁打开其实都行,比如这个bener viewer打开的话看一下。
10:08
后边咱们讲这个资金码指令的时候呢,会给大家说这个事情,也就是说咱们讲到这个中篇的时候啊,这个呢,是咱们把这个资金码文件呢,放进去以后,给我们呈现出来,这个16进制啊,就长这个样子。就这这样子,这呢咱们用它看看现在不是咱们要讲的这个时候啊,所以呢,我就关掉了,那我们应该怎么看这个资金码文件啊,咱们此时呢,进行一个哎反编译,那这个反编译的话呢,咱们主要呢是有两种途径啊,后边咱们讲中编的时候呢,也会说那一种方式呢,就是咱们使用这个扎P啊,这个命令啊,另外一个呢,就是简单一点,咱直接呢放到这,那我这块呢,有个view接class lab是不是直接在这呢,也能够呈现出来呀。没问题是吧,哎,这样。好,这个呢,咱们先放着啊,咱们先这样来看。这个呢就是已经高度集成了,咱们呢选中当前这个词件码文件,然后点右键,这个呢叫open in a terminal。
11:00
奶,来到我们这个控制台,这在这的时候呢,咱们使用这个jarp jarp呢进行一个反编译,我们叫反解析啊,然后呢,杠V啊,就是我boos,然后这个再来一个叫杠P,杠P的主要目的是什么呀?就是我们这里边会存在的一些权限比较小的一些属性或者是方法,要是没有加杠P的时候,我们这个私有的这些结构啊,就不能够给我们反解析出来了,你要是想让这个不同权限的都能够出来,把这个杠P呢加上好,那在后边呢,咱们写上叫method inner。Struck test t class不要加分号了,然后呢,诶这时候我要一回车,其实呢,就能够把这个翻编译过来的这个信息呢,直接给我们呈现出来,但这时候咱们这样看呢,是不是不太方便哈,好,那这时候呢,我再这样处理一下。诶先CTRL上把我们这个整个结构呢,还调出来,然后呢,我这传入到一个比如说叫test test点。Tit文件中,哎,这样子啊,一会车。
12:02
搞定了,搞定以后呢,我这用的是一个相对路径,所以呢,这时候大家就会在咱们当前这个Java目录下看到这样一个test.tt啊CTRLC一下,咱这呢就放到这个桌面上,这样呢我看起来会方便一些。嗯,行,这个我们说do you want,这个来否好来看一下,那这呢,就是咱们刚才这个,呃,反编以后得到的这样的一个T文件啊,就是我们这块打开看一看,那刚才呢,咱们提到说这个嗯叫什么呀。叫我们这个方法区呢,都能放什么信息,那此时呢,咱们看的呢,实际上是这个自解码文件啊,那这个自解码文件呢,经过这个呃,Class loader进行加载之后呢,咱们就会把它呢,其实关于这个类的相关的信息啊,都会放在咱们的方法区,那么通过这个词件码文件呢,其实我们也能够看到说你当前这个类呢,都有哪些东西,哎,说白了就是这个意思啊行,那刚才呢,我们一开始提到了一个叫类型信息,那类型信息这块呢,就涉及到你这个类的一些基本东西。
13:04
好,那大家呢,你可以来这看一下,关于我们这个类的,你的这个呃权限是吧,诶你的这个权类名,你的这个父类,你实现的这个接口。放这儿,你实现这个接口,接口呢,它的所在的这个包,然后呢,你这个泛型呢,它所在这个包啊等等是不是记录的都是非常清晰的呀,没问题是吧?诶所以这块呢,咱们可以理解成呢,这就是咱们所说的这个叫类型信息,咱们在这个自解码文件当中包含了你当前这个类的一个比较完整的情况,完整的信息,那这个信息的话呢,也会保留在咱们这个使用class loadr加载到的这个词解码,呃,加载到的这个这个方法区当中。啊,是这样子的,行,那咱们这个自解码文件里边是没有显示这个class loader的,你看我这CTRLF一下我去,诶输入一个这个叫class loader,大家呢,去搜索你发现是找不到的是吧,因为不可能找到嘛。
14:03
能理解吧,就是我们这个自解码文件,这呢是咱们看的自己码文件反编译的,咱们这个说的这个程序加载这个过程是先有这个自己码文件,咱们现在是对他的进行了一个叫反编译,对吧?然后呢,我们使用这个class load呢,加载到内存中的时候,诶把我们这个相应的自解码文件中的这个信息呢,都放在这个方法区,这个时候的方法区里边其实不光放有咱们现在要看的这个这个反编以后的这个信息,同时呢,在我们这个方法区里边,实际上它还保留了,就是你这个自解码文件使用的哪一个类的加载器,加载进来的这个类的加载器呢,也在我们当前这个类的信息里边是有记录的,诶这个大家要注意,因为我们后边涉及到方法区的回收的时候呢,就是你要是相应的这个类的加载器,比如说没有用了内的加载器,对应的这些类呢,也就相应的也会被回收。再说一遍啊,就是我们加载到方法区中的这个类里边,它是记录了它是被谁加载的,也就是说呢,它的class loader,那另外的话呢,咱们这个class loader呢,加载到这个方法去,它也是会独立加载的,对吧,这个class loader呢,它也会记录它都加载过谁。
15:14
大家彼此互相记录,就是这样一个情况。咱们在现在这个class文件当中是看不到的,这个大家应该都明白,因为咱们这块呢,是你看的这部分是吧,咱们没有去经过这个呃,Class的加载啊,所以在这里边你是看不到的这个克拉斯的这个身影的,行,那么包括呢,咱们说的这个类的一个修饰符是吧?诶这块都有显示啊,嗯,刚才呢,这我们说明的是这个叫类型信息,那以及的话呢,我们还有这个叫预信息,就是所谓的这个咱们常常呢称为叫属性,这个大家往后找,那这个找在这呢,就是我们这个相应的这个预信息。哎,就是我们现在看到这个信息,注意咱们不是在这个内存中去看的,咱只是看到这叫自解码文件,这个的信息呢,都会使用class呢,给我们加载到这个方法区的,关于你这个域中的名字,这个呃,类型啊,你的修饰符啊都有是吧?那这呢是我们这个叫呃四针形的itr,它呢类型是什么,在这写着呢。
16:14
那在这写着是吧,然后呢,你的呃是private的是一个static,诶这呢,对应的就是我们刚才提到的说关于你这个域的,诶是不是这样的几个部分啊。都有说明是吧,而且呢,他还记录它的一个相关的声明顺序,咱们在这里边呢,声明的顺序是先有number,后有str,那在我们这里边呢,也是一样子的,先有这个number,还后有str。哎,那如果说你代码当中交换一下的话呢,我们这个自源码文件回头也会交换过来。啊,这个注意一下行,然后下边的话呢,是关于我们说的这叫方法是吧,那方法这块呢,就比较丰富一些。啊,方法的话呢,大家首先注意到我们这儿呢,是不是有一个构造器。这个构造器,那这个构造器呢,本身咱们在类中我刻意的是没有声明的啊,我是没有声明的,咱们说呢,也会给我们默认呢,是不是提供一个,诶这呢,就是咱们看到的提供的这个构造器,这个构造器呢,在咱们这个自解码文件里边呢,其实它对应的也叫做方法啊,实际上呢,是一个叫in一个方法。
17:14
啊,就是我们这个。哎,Int这样个方法啊,这个大家注意,哎,这呢是我们要说的,这叫方法信息啊。行,那也就是说呢,从咱们这个字节码的角度来看的话呢,构造器也好,还是咱们所谓的这种普通的方法也好,不管你是不是静态的啊,其实都叫做方法,在咱们源代码层面呢,构造器是构造器,方法是方法,嗯,这个大家要注意一下,咱们叫法不一样啊,行,那么再回过来。那关于这个方法这块呢,这个信息呢,就比较丰富了,那咱就不看构造器了啊,咱找一个比较典型的,以这个T1为例,那关于这个方法的它的这个诶,参数情况,返回值类型的情况,这个大V呢,就是wide的意思,然后呢,这个方法它的一个权限啊,Public的下面呢,就是我们所说的这个方法内部的这个叫。
18:02
这个这叫什么字解码是吧?诶这个字解码,这个字解码里边呢,也会记录咱们当前这个方法,它的这个叫操作数占的一个深度三。局部变量表这个长度二局无变量表,我们说是一个数组,所以这个数组长度是二,那这个操作数占呢,它是个占结构哈,最长最大的这个深度呢是三,然后这呢是咱们这个叫参数的一个,呃,大小啊,对于我们这个非静态的方法来讲,呃,一是吧,就是咱们有一个是不是当前的这次对象啊。这次引用是吧,就是记录了我们这个基本信息,那关于咱们这个叫那静态的这个结构,那这个静态结构这写的也是一,这个一呢,主要是我们这个行参,这个是伊朗,那你静态的话呢,它就没有Z次对象了,对吧?那这个大家注意一下,那这个静态方法里边这个它的反之类型呢是in特型,然后呢,这个它的权限修饰呢是public,嗯,就是修饰符呗,Public,然后呢,还有一个叫teady的一个声明,这呢是它这个操作站的一个深度啊,局部变量表的一个深度啊等等啊这块呢是都有记录像这些信息啊,咱们呢叫做方法信息,这个方法信息还有刚才呢叫运型息,还有这个类型信息,诶都会呢加载到啊,通过咱们说的叫类的加载器,加载到我们这个方法区里边,这呢,就是大家看到最初加载之前的这个自解码文件中的这些基本信息。
19:21
啊,还包括呢,咱们刚才是不是提到了一个叫,嗯,看上边了。嗯,TEST1TEST2我们看哪个里边有这个啊,这个TEST2里边我们有个异常对吧,那我们还提到这个方法的话呢,它可能还会有异常,这呢还会有一个叫异常表,第一常表呢,对应的我们这呢叫exception table。啊,从哪到哪,这个目标是什么,这什么意思啊,这个from哪吐哪二到九啊,大家就得看这了啊,从二到九就是我们诶这几行,这个二跟九呢,是咱们这个自建码文件当中它的这个行数行号,那这个23呢到27呢,是咱们这个代码当中23行到27行,那回过来23行。
20:03
是不是这一行,27行是不是这一行,也就是说这几行代码。这呢是我们要考虑的,在这个踹当中的这个结构,也就是说我们这个异常表它呢,能够这个包裹住的这个主体的一个范围,那在这个范围当中,如果说没有出现异常,这有一个叫target。对吧,诶先看这吧,这个goto就是我们这个九的话呢,如果你到了九啊这块有个GOTO17,这个17呢,对应的我们这个是28行,就是如果你要执行到这个九的话,执行到九呢,意味着就是我们是不是到这了啊,你要执行到这的话呢,它就对应的我们这个字解码里边这个叫17,这个17的话呢,在这对应的我们代码是第28行,那就相当于是你要能执行到这儿,嗯,那就相当于直接呢就有个return了,哎就出去了是吧?诶就这个意思啊。行,就这块呢,记录了咱们这个,诶这个异常的信息,异常表里边记录了我们这个所能够这个包裹住的一个区域是多少啊,出现异常的话呢,目标它给的十二十二是吧,诶对应的我们这儿就是你出现异常的话呢,这25 25的对应的是我们这个,哎,它就出现异常了,说白了是吧,哎这呢就进行一个异常的处理。
我来说两句