00:00
那讲完了程序计入器以后呢,咱们来看下一章,呃,下一章呢,叫做虚拟基站,那以前呢,我们也叫做Java站,这一章呢,是我们这个讲运行时数据区比较重要的一章啊,站堆方法区啊,这三章呢,算是比较重要的这个章节,那我们来看一下这一章呢,主要涉及到的内容,那首先呢,是关于虚拟战的一个概述,讲到它的一些基本的特点,然后下边呢,提到战中的存储单位啊,这个存储单位呢叫做战争。然后呢,下边提到了,呃,这个战帧里边又分成几个具体的结构,比如说呢,叫局部变量表啊,也称作叫本地变量表,然后操作数占啊,Oper stack,然后下边呢,我们举一个例子啊,基于局部变量表和操作站诶,我们给大家举一个例子啊,这里边呢,又涉及到这个资金码指令的一个执行啊,我们这叫代码追踪,然后呢,占领缓存技术。啊,接下来呢,叫做动态链接啊,Dynamic link,这也是我们战争当中的一部分结构,然后基于动态链接以后呢,我们谈一个方法的调用啊,解析和分派,大家平时呢,在开发中呢,呃,那方法调用呢,肯定少不了,那具体呢,我们看一下它的一些细节啊解析和分派的情况,再下一个呢,叫做方法返回地址,这也是咱们战争当中的呃,一个结构,这个return address。
01:18
嗯,回忆一下我们刚才说的几个结构了啊,一个呢叫局部变量表,第二个呢操作入站,哎,第三个呢叫做动态链接啊,第四个呢叫做方法返回地址,那除此之外就是前面这四个呢,是我们说呃比较重要的信息啊,那如果呢,还有一些附加信息的话呢,我们还可以可选的有一个叫一些附加信息啊,这呢一共是我们战争当中的几个部分,我们依次做介绍,最后呢,我们再来看一下这个站相关的一些面试问题,这呢就是我们整个这个虚拟站啊,我们要讲的这11个问题,那首先呢,我们来看一下关于虚拟站的一个概述,那提到这个虚拟站呢,首当其冲的仍然是我们官方的规范当中关于虚拟站的一个说明,这个呢,回过来以后呢,呃,第一个呢叫PC register啊,就是PC寄存器,然后呢,下一个就是Java virtual machine stas,这呢就是讲的我们Java虚拟站。
02:11
啊,显然这个虚拟站呢,比我们这个PC寄存器呢,稍微的多那么两行是吧,诶大家呢,可以把这个呢读一读,我这呢就不带大家去读了,那已经呢,把相关的一些这个信息呢,咱们就集合过来了,像一会我们提到这些信息呢,我都相应的翻译成了咱们的中文了,所以大家呢,直接来看我们这个中文的内容啊也是可以的。那首先呢,我们提到这个虚拟站出现的一个背景啊,前面呢,咱们其实已经讲过Java虚拟机的一个架构模型了,咱们是基于站的一种设计啊,站的一种架构方式,那它的好处是什么呢?就是实现跨平台。哎,我们说这个站的方式呢,跨平台这个是比较方便的啊,那基于寄存器的方式呢,它跟这个具体的CPU呢,耦合的比较高,那跨平台是他的其中的一个优点,另外呢,叫指定级比较小,那我们说是八位的啊对齐的,那占这个寄存器的话,像单位虚拟机是基于寄存器的,它是16位对齐的。
03:08
然后呢,编译器呢,很容易实现,那这也是比较容易实现,这个像我们说站结构呢,只有近站出站,缺点的话呢,就是性能下降啊,相较于我们寄存器来讲性能要差一些,那另外呢,就是它的指令更多。咱们前面呢也总结过了,所以这块呢就不多说,作为一个回顾,如果这块忘了呢,大家再把我们第一章中讲的这个。呃,虚拟机的一个架构分成站和寄存器两种方式啊,再熟悉一下啊。好,下边这个说不少Java程序员呢,一提到Java的内存结构就会非常粗力度的呢,将Java信拟机中的内存呢,理解为仅有堆和栈这两个结构啊,大家回忆一下,你看你是不是有这样的行为啊,一提到说内存啊,首当其冲说只有站,只有堆,或者呢,想到的只有栈和堆。
04:00
啊,那这个为什么呢。啊,这个错了,还得问一下为什么是吧?呃,首先说呢,我们说这种划分方式呢,是不全面的啊,这个理解呢是比较狭义的,但是从另外一个方面来讲呢,呃,说明栈和堆是我们内存当中最重要的两个结构。啊,也确实是我们程序运行的关键啊,是这样的,另外呢,诶我再给你找个借口,这种划分方式呢,有可能是你之前学习过C或C加加,那C或C加加呢,它的内存布局结构呢,诶主体上就是栈和堆了,那由于受之前的这个影响,所以你会误认为咱们Java的虚拟机当中内存也只有这两个结构,那Java呢,其实比他画的呢,还要更细致一些啊。好,这呢就是我们一个初步印象。然后呢,我们看这里边说明的说,站呢是运行时的单位,而堆呢是存储的单位,换句话说呢,占我们可以理解为呢,它管运行,而堆呢,它主要是来管存储的。
05:01
啊,说站解决程序的一个运行问题,比如说程序该如何执行啊,这个如何来处理数据啊,诶我们把这个相关的一些指令,那我们呢,诶,通过站里边的局部变量表,它的这个操作数站,哎我们来体会,大家现在猛一看,可能还不是特别清晰哈,嗯,你先有个大概印象,咱们呢,讲完这一章以后,你再翻回来看这个内容,你会更加的清楚。啊,是这样子的,那么说堆呢,来解决数据的存储问题,说数据应该怎么放,放在哪儿呢?主体的数据呢,都在堆中放。当然了,也不全部啊,咱们说对象呢,主要是在堆中放的,那如果你要是方法内的一些局部变量的话呢,咱们还是放在占空间当中的。当然这个局部变量我们得说清楚,是基本数据类型,你要是引用数据类型的话呢,在占空间只是放这个对象的一个引用,咱们Java呢,说是面向对象的啊,或者我们有个词呢,叫万事万物皆对象,那只要是对象那都得是在堆空间,所以主体上我们说数据呢,都放在堆空间当中啊,是这意思啊,不是绝对的啊,占空间它也是可以放一些数据的,像局部变量的一些基本类型的数据,或者引用的对象的一个地址啊,是吧,也是放在这个占空眼中的啊,这要注意,那由于我们这个对象又比较多呢,呃,这个,所以。
06:19
或者说这个对象呢,是我们这个程序存储的一个大头了啊,所以说咱们这个堆空间呢,在整个这个内存空间当中。你看在咱们整个这个,嗯,内存空间当中,我这儿呢画的这个图,运行时数据出区呢,不是成比例的来画的,不是说呢,这个堆和我们这个PC寄存器呢,你看诶它俩好像差不了几倍,不能这样来理解啊,呃,这样呢,不是成比例的缩小的这个堆空间呢,是我们运行时数据区当中呢,最大的一部分区域。当然呢,你说它最大呢,也也也不确定哈,也也不能说肯定的,因为我们还可以设置这个对待大小,你要设置它这个没有我们这个方法去大,因为方法区呢,现在我们都可以使用这个本地内存了啊,它的空间呢可能会更大。
07:06
嗯,因为他用的是物理上的内存了嘛,是吧,你要设置它这个是比如说256兆,那剩下它可能有几个G呢,是有这种可能性的啊,嗯,那就这样说吧,先不考虑方法区的话呢,它是最大的,这个没毛病啊,行,这呢就是我们说的这个堆空间在内存中呢,其实是比较大的一个区域了,占呢不是特别大了哈。那么如果你对这个站馆运行堆管存储呢,还不是特别的熟悉,你看我特意呢,这个放了一些图,这个网上我想找一个哪个菜比较好,然后呢,诶最后呢,是选择了这个佛跳墙,这是广东的一道名菜啊。那么中间一道线,这个线的左边呢,大家可以理解成就是站,它的右边呢,就可以理解成是堆。啊,是不是还有点儿用心良苦是吧,这个你看一下啊,嗯,上边呢叫食材,嗯,我们都有哪些具体的原材料,你可以理解成是我们的变量。
08:07
然后下面的话呢,是具体的做法,第一步第二步第三步啊等等等等,那是这些步骤上面呢,就好比是这些变量,我们通过相应的一些自检码指令啊,按照这个指令呢,去执行,是做这个store啊,还是put呀,Push啊,还是说我们做一个ADD呀等等这样一系列的这个操作。这呢,都是我们这个占空间来做的啊,涉及到局部变量表,还有呢,就是操作数站,OK,然后呢,在堆空间当中,我们具体做这些事儿啊,你知道说放入广度诶,就具体的这里边有一步啊,我们就做那个操作,针对这个对象呢,我们做一些呃,值得修改啊,运算啊,这就是我们堆控件当中真正来存储这些数据的。啊,大家有一个这样比较直观的认识啊就可以了。行,那咱们接着往下再来看哈,说Java虚拟机站是什么?
09:01
啊,Java virtual machine sta早期呢,也称为叫Java站啊,你就现在就叫做Java虚拟站啊就可以了。说每一个线程都要注意哈,说每一个线程呢,在创建的时候呢,都会创建一个虚拟基站啊,内部保存着一个一个的战帧,对应着一次次的炸va方法的调用,诶也就是说呢,这里边有两个信息啊,第一个就是每个线程在创建的时候都会创建一个虚拟站,也就它是一个线程私有的,跟咱们上一节讲的PC寄存器是一样的啊,是线程私有的。这是第一个问题,第二个问题呢,就是我们站里边存的是什么,这里边我们提到了,它保存的是一个一个的战针,这个stack frame战针呢,就是咱们站里边存储数据的基本单位啊,叫做战针,记住它那么一个战针就对应着一个Java方法。啊,一个战争就对应着一个Java方法,嗯,简单来说,举一个例子。
10:06
举个例子,咱们现在又是第五章了啊。那就章打开,哎,我我这放了俩先不用管啊,我们现在呢,写一个程序,咱就叫做。哎,Stack的一个测试啊。行在这里边儿,比如我们写一个public word,我叫一个方法A。在方法一里边,我比如我定一个变量I值是十,呃,定一个变量接呢是20,然后呢,我在public y的,哎,我定一个方法B。这个里边呢,我定一个K呢,是一个30。M呢是一个40。行,然后呢,我在这个方法A里边呢,我调用方法B。行这个代码呢,我就写完了,那如果我们这个方法A啊,在被调用的时候,哎,我这是用的一个非静态的方法啊,他要想被调用的话呢,比如我们在这个main方法里边,哎调的话呢,我们需要创建当前这个类的对象了,就。
11:19
行,那我们第二方案A,就是这块创建对象的这个过程,在堆空间中,占空间中的分配,我就忽略掉了,我们主要来看这块啊,诶在内存当中,我们现在是有这样的两个方法,它的一个调用。简单来画一下,大家有这样的一个意识。跟着V粘过来。哎,这呢我就放到这儿了啊,那我们当前呢,是一个主线程,主线程当中执行这两行代码,所以这就只有一个线程,这一个线程的话呢,我们就用一个站来表示了,咱们刚才也说了啊,一个线程对应一个Java虚拟机站啊,这就是它了,填充的话我们来一个空的啊。恩,颜色。
12:01
来一个红的吧。行可以了啊,那么嗯,当我们执行这个method a的时候呢,我们相当于是把这个A的方法呢加载进来以前啊,咱们说一下以前咱们画的时候,就是我上这个Java基础课的时候呢,带大家画都通常是这样画的啊呃,因为那个时候呢,咱们还这个不给大家讲的这么细致的说,方法A调用的时候呢,我们在占空间中,因为你是一个局部变量嘛,呃,局部变量呢,就会在占空间中去存放,我们这儿呢出了一个十,然后呢,阶呢是20,那20呢往上移一下,这呢是一个阶。然后呢,这个变成20了,在方法A呢下边又调用了一个master b master b呢一执行又定义了一个K。哎,再往上。K呢是30。然后接着又有一个M是40。
13:02
40好,原来的时候呢,都是这样子画的,接下来你再做一些运算啊等等啊就完事了,那其实的话呢,我们这个呢,稍微的应该再优化一下,当然现在优化呢,我们还不是画的那么细致啊,把这两个呢加个框。大家加个框。我换一个颜色,然后呢,诶上边这个呢,我们也加一个框。这我用一个。绿色吧,行这样子啊,嗯,那我们说呃,这一个框代表的就是一个,大家说代表什么呢?哎,你可以说是代表一个方法啊,那我们现在呢,先把它称为就代表着一个战争。那其实呢,我这写的也不是特别的精确哈,因为咱们战帧下边呢,还要细分成局无变量表操作数站这个动态链接,呃,返回地址等等,诶我们先这个比以前讲的再细致1.1点点,我们往里边看哈,就跟说看到一个大象,你首先看到它有胳膊,呃呃,不是没有胳膊了哈,他有四条腿,有鼻子,有象牙,呃有有头等等,然后你再往里看呢,说啊,他有这个。
14:22
呃,细胞是吧,细胞再往里看呢啊,有细胞核,细胞质,呃,线粒体等等,呃,我们一点点往里深入啊,那咱们现在呢,先看到的就是占空间当中,放在这几个变量呢,因为它归属的方法不同,我们都加了框,这一个框呢就代表着一个战针,然后呢,我们说一个战针就对应着一个方法。诶,也就是说呢,每一个方法都跟一个战争是一一对应的关系,呃,那很显然呢,咱们在调用这个方法B的时候,这个方法B呢,目前是在这个占顶,所以我们把占顶的这个方法呢,就称为叫当前方法。
15:04
啊,就是当前方法,那当这个方法B执行完以后呢,这个绿框呢就出战了,它一出战呢,那么方法A呢,又变成了当前方法,诶是这个意思哈,我们这呢,首先你得有个加框的这样的一个概念。啊,就是这里边儿我们保存了一个个战争一次次的方法调用,就类似,呃,就对应着一个一个的战争的入战和出战操作啊这样的。行,下面提到说我们这个站的生命周期呢,跟线程是一致的,因为呢,我们是随着线程的创建而创建的,那自然而然呢,就随着线程的消亡而消亡,当我们啊这个主线程的method a执行完以后呢,这个主线程就结束了,主线程结束,咱们当前这个虚拟基站啊也整个呢就结束了,它的生命周期就结束了啊嗯,也很好理解,下个呢说作用,它呢主管Java程序的运行,保存方法的局部变量部分结果,并参与方法的调用和返回。
16:06
啊,局部变量啊,这个局部变量呢,我们再稍微的强调一下是吧。这个局部变量。嗯嗯,咱们讲这个变量的分类哈,以前说过这个局部变量呢,它是相较于我们说的这个叫成员变量来说的。这个成位变量呢,我们也称为呢,叫属性。诶,它俩是一个层面的划分啊,然后另外一个层面的划分呢,我们称为叫基本数据类型变量。诶,还有呢,叫引用类型变量。像我们说的这个类,哎类数组,还有这个接口等等,这都属于叫引用类型的变量,哎,是这样子的,那就比如说我们说人啊,人呢,可以按性别分成男人和女人,呃,按照这个人种呢,可以分成这个白种人,黄种人啊,这个还再多一个,比如说黑种人是吧,或者我们叫黄种人和非黄种人也行,那么男人当中是不是就有是白人或者是黑人对吧?哎,也是他呢,是可以交叉这样的组合的啊,那我们这儿呢,说存的是局部变量,那意味着这个局部变量呢,就可以是基本数据类型,也可以是影数据类型,诶所以这呢,我们一定要明确一下啊,这个局变量呢,如果是基本数据类型,那就可以是叫八种。
17:34
基本数据类型。那引用数据类型呢,注意那我们说了主要就是对象了啊,那这个引用数据类型我们只能放,哎,叫对象的引用地址。呃,真正这个对象new的这个对象本身得在堆孔严中去放啊,因为堆管存储嘛啊,然后部分的结果,呃,我们中间运算的这个结果呢,也会给它存储起来,参与方法的调用啊,我们在A方法中调用了B方法,在参与方法的调用,然后还有它的返回啊,返回就是一个return。
18:10
啊,就是个return的过程,这个咱们在嗯前面看这个反编译的时候呢,大家应该也见过,你看咱们这是之前写的这个may方法啊,正常最后结束以后呢,你看它还有个return,这个呢,是没有返回值的,是这样return,那如果有返回值呢,它就是另外的这个操作指令了,行是这样子的情况啊,诶那关于它这个作用呢,我们就诶说清楚了。好,下面再来看。说站呢,是一种快速有效的分配存储方式,它的访问速度呢,仅次于程序计数器,那程序计数器那没人能够超过它,它就存储于下一条指令的地址,谁能超过它对吧?它的速度肯定是最快的,你要还想比它快,那就只能什么也不存了,那肯定更快是吧?诶它它是最快的啊,然后这个站的话呢,仅次于它,诶它涉及到进站出战,进战出战诶就没了。啊,像我们操作数组啊呃,队列啊等等,那比它要复杂一些,因为它只针对于占顶的元素进行操作啊,所以呢,也是比较简洁的啊,速度也比较快。
19:09
然后呢,针对于这个战的操作呢,说只有近战和出战,这个很好理解啊,就是当我们每执行一个方法的时候,这个方法呢,对应的一个叫做战争,他就进战了,我们叫做压战啊也可以。呃,叫做这个push是吧。然后呢,当我们这个方法执行完的时候,像刚才我们这个方法b methodb,如果执行完了,它就要出战啊,我们就叫pop啊,这要出战的一个操作。那出战以后呢,之前的那个战呢,它就变成了站顶的一个呃元素了,那之前的那个战争是吧?呃,或者说之前那个方法就变成了这个占顶的一个针或者是方法了。诶,这个呢,非常好理解啊,就不用多解释了,那下一个问题说对于站来说是不存在垃圾回收问题的。啊,不存在垃圾回收问题的,这个再回顾一下,咱们讲上一节的时候呢,这不是提过这样的一个问题嘛,就是关于我们运行时数据区中的这样的几个结构呢,大家从两个方面去看哈,第一个呢叫做JC,呃,第二呢,是不是有这个呃异常啊,这个我就写成叫OM了哈。
20:16
哎,看看是不是从这两个方面呢,大家去理解啊,对于咱们上一节讲的叫程序计数器来讲,它既不存在JC,也不存在OM。啊,它就是存这个地址的下一条指定的地址,这些回收啊,不用回收,回收啥呀,是吧?不用回收啊,他寄个地址,然后他寄个地址,他他也不会移出啊是吧?所以这俩问题它都没有啊对于咱们的站来讲呢,站是存在OM的,一会儿咱们展开说啊,它存在OM,但是呢,它不需要JC。就是你要呃,超了他的这个空间了,它就溢出,那一出就挂了。对吧,它就会出这个我我写成OM啊,诶也可以有这个站一出这样一个操作啊auto memory这是它另外的一个异常啊,它可能会存在这个内存溢出,但是呢,它用不着你去垃圾回收,因为它只有进站出站这个操作。
21:07
啊,通过这个呢,来实现这个数据的这个出去进来,你用不着使用一些复杂的算法进行一个JC啊是这样子的啊。呃,这个呢,就是我们典型的一个战的特点啊,近战出战只能是从同一端来实现啊,这个就好比是生活中大家这个比如打手枪装的这个弹夹是吧?呃,弹夹呢,你一个个往里边塞子弹,最先的子弹是放在最下边的,最后打出啊,最后塞这个子弹呢,是先打出去的,这就战的特点,就是叫first in。哎,Last out,或者呢叫last in,哎,First out,这个呢是我们站的特点,那对应的还有一个结构呢,叫做队列。那这个大家下来呢,你可以再去熟悉一下我们说的这个数据结构啊Q,呃,队列的特点呢,就是first in first out。那就是先进先出,典型的就是大家天天你排队,只要你排队那就是队列啊,这个我们这个通常老百姓所说的先来后到啊,你先来的就先服务你,后来呢,你就往后排队是吧?哎,这就是队列的一个特点啊。
22:12
行,那这儿呢,我们对这个站的这个基本内容呢,有了一个介绍,大家应该整体上呢有一个感觉了。
我来说两句