00:00
好,那接着呢,咱们再往下看啊,这呢说这个扎va逊集规定说堆啊,可以处于物理上不连续啊,这儿呢,大家呢,经常应该会听到这个词叫物理上不连续啊这种我给你加上一个标识是吧。嗯,把这个打开。哎,红色叫物理上不连续,但是呢,在这个逻辑上呢,它又是连续的。嗯,逻辑上是连续的,那很多同学呢,可能一开始呢,不理解这个问题啊,说为什么说这个逻辑上它得是物理上不连续,逻辑上又得是连续呢?哎,首先呢,我们说这个逻辑上连续啊,嗯,那其实的话呢,我们讲这个咱们磁盘上的这个存储文件的时候呢,这个文件呢,其实咱们也不一定非得要求是不是说都要连续啊。啊,现在磁盘中我放在这么多文件,这个文件呢,物理上呢,咱们,呃,这个就是先逻辑上吧,逻辑上呢,我们其实也没说非得要连续,对吧,但是呢,连续的好处是什么呢?就是对于我们这个大的这个数据,大的这个对象的话呢,如如果说逻辑上连续的话呢,首先呢是实现比较简单,直接呢,就分配一块连续的空间,那其的话呢,我们存储呢也比较高效,对吧,它直接呢就放一起,这叫逻辑上连续啊,这是其一啊,那逻辑上连续为什么物理上呢又可以不连续呢?
01:11
啊,这呢就涉及到一个呃,虚拟映虚拟内存的一个问题了,就是我们这个物理内存跟这个虚拟这个逻辑上的这个内存的话呢,我们可以建立一个映射表是吧?哎,那这个映射表呢,就可以把这个物理上实际上不连续的这个内存呢,在我们这个虚拟内存层面呢,看到都是连续的,哎方便呢,我们在连续内存情况下呢,去存储数据嘛。哎,所以这块呢,大家要去理解一下我们这个堆的一个要求啊。好,下一个的话呢,我们提到说所有的线程都共享堆,哎,我们已经说过了,哎,但是呢,在这里边我们还可以划分叫线程私有的叫缓冲区。啊这呢,如果问到一个问题说哎堆空间,哎一定是啊完整的这个堆空间的所有啊都是共享的吗?哎这呢,要提到说不是的。啊,因为这呢,还提到一个叫TLED这样一个空间啊,这个空间怎么理解呢?大家这样想啊,咱们一个呃,进程当中多个线程,大家如果真的都共享这个堆的话呢,这个堆是不是毫无疑问就是一个共享数据啊,那么共享数据大家学过多线程哎,是不是就会存在线程的安全问题。
02:16
大家都去操作这个对啊,都去,呃这个这个做一个共享数据的一个调用啊,那这时候呢,可能就会存在相应的一个问题了,那既然存在线上安全问题,我们要用同步来处理的话呢,你相应的这个对空间它的这个并发性呢,是不是就非常差了。对吧,变化性就非常差了,那怎么办啊?哎,那这时候我们在这个堆空间里边,咱们再给它分出一部分小空间来,这部分小空间呢,我们再给它打成好几块,哎,每一个线程呢,分一块。每个线程分一块,那就意味着我们这个小块的话呢,是不是就属于线程,呃,独有的了,每个线程都有一份是吧,那每一个这个小块呢,我们就称为叫T。哎,每个线程都有的,那么这个时候呢,在这个TLB这个空间当中,每个线程因为是一份,所以他们,哎又体现了另外一个点,是不是叫并发性更好一些,哎就是通过这个角度出发啊,我们分出来这个叫TLED。
03:08
啊行,哎,这就过了啊,然后呢,再往下说呢,Java虚拟一规范中对堆的这个描述呢,是这样子的,说所有的对象实例。啊,你看我这块呢,是不是额外的强调了一个词叫所有的是吧,所有的对象实例以及数组呢,都应该,哎在运行时呢,哎分配到这个堆上面。哎,分配到这个堆上面,这里提到说这个堆啊,它是一个运营时的一个数据区。然后呢,这个内存啊,是用它这个空间呢,是用来存储for all是所有的类对象。还有我们所有的这个数组。哎都应该分配在对上,那这呢,我想哎强调的一句话什么呢?哎,我想在这个哎all之前呢,加上哎,或者把这all呢,咱们替换成一个词啊,叫做almost。哎,Almost这个大家应该理解哈,就是几乎所有的。啊,这个嗯,几乎所有的人啊,都是这个善良的是吧,Almost,这个哦,是吧,Person啊。
04:06
善良的是吧?善良这个单词还不大好说啊,哎,就是这个almost就几乎所用,那也是有一些恶人存在的,对吧?哎,这就是almost几乎的意思,那为什么我这块要加一个几乎呢?说你这块敢挑战扎va虚拟规范是吧?哎,这个咱们到后边呢,我给你讲解啊,Java虚拟规范为什么还用哦,我这块为什么要强调几乎这呢?其实存在一个否定之否定这样的一个观点啊,咱们先埋下一个伏笔啊,那么首先呢,我们先理解一下,为什么我这块的强调要几乎。嗯,应该这样说,咱们在这个堆空间中放这个对象实例啊,放的话呢,其实就很花费这个时间,后面呢还要涉及到垃圾的一个回收是吧,那我们这个扎va逊尼呢,在进行不断的这个更新迭代过程当中,为了让这个性能更加的提升,这块呢,引入了一个叫做逃逸分析。啊,这个大家有的可能听过啊,这个逃逸分析,这个逃逸分析当中呢,我们去判断说你这个方法中的这个,比如你的对象呢,是不是发生了逃逸,如果没有发生逃逸的话呢,我们可以进行一个叫占上分配。
05:03
哎,这争分围包括呢,我们后边还有一个叫标量替换啊,这都是这个新的这个概念啊,那么这个概念的话呢,咱们实际上是在这个,诶第九部分呢,给大家去讲解的。那因为呢,它出现了这个站上分配了,所以说呢,你这个对象呢,是不是就不能说,哎,所有的对象都在堆里边去分配了吧。哎,所以呢,这块我用了一个叫几乎啊,因为还有可能是不是在站上分配啊。哎,理解一下啊。好,那么这个呢,咱们先说到这儿啊,那么再接下来说这个,呃,数组合对象啊,可能永远都不会存储在站上,刚说了一个战场分配,说永远不能分配在站上是吧?这个呢,咱们讲到最后的时候,咱们再说大家呢,先去构建咱们关于这个堆的一个最初的一个架构。是吧,再先去构建一个最初的架构,就跟说嗯大家,嗯应该这样讲啊,应该这样说,就跟咱们现在教大家知识呢,有点像咱们小学呢,嗯,教大家学这个算术,咱们在小学的时候呢,是不是这个智力水平都比较差呀。
06:03
啊,也都属于这种叫弱智的一个阶段是吧,智力水平比较差,比较弱嘛,现在呢,属于一个这个叫强制的一个阶段是吧?啊这个在你比较弱智的这个时候啊,这个弱智不是咱们说的贬义词,智力水平没这么高的时候,老师教大家学习的时候都说什么呀?哎,说咱们出个填空题,说最小的数是集。大家呢,是不是特别稳妥的写了个零,说最早数是零啊,老师这块看答对了啊,这个就是个正确的,然后当你上了这个四五年级的时候呢,咱们是不是接触了负数了。啊,那么以后呢,是不是还接受这个所谓的叫负无穷了是吧,说最小的数是几,这个时候你是不是就不敢写零了啊,这时候你要写零是不是就错了,诶因为呢,我们这个数呢,是不是没有最小的呀,因为负数可以到负无穷是吧?哎,也就是我们在不同的阶段呢,我们这个认知水平不一样,所以我们的理解呢也不一样,就跟说咱们上至少我啊我上大学的,我上这个高中的时候呢,咱们还主要讲是不是牛顿的三大力学定律啊,哎,我们称为叫经典力学了。啊,那么咱们还讲这个爱因斯坦。
07:01
啊,爱因斯坦还有这个叫啊波雷尔象性是吧?啊等等啊,那现在这个物理学的发展是不是已经会打破我们原有的关于这个力学的一些观点了啊,就物理学呢,在不断的进步啊,人呢也在不断的进步,所以我们以前看的对的东西呢,现在看可能就不对了,或者说呢,是具有局限性了。哎,应该这样去理解啊,那咱们现在呢,教大家学习这个,呃,对空间这个知识的时候呢,其实也是这样,咱们呢,先是从零到一。啊,然后呢,这个后边呢,咱们再讲一些高级的内容,你发现了,原来从零到一的有些东西呢,可能是有局限性的。哎,应该是这样啊,就是相当于这块呢,先教你的就是最小的数呢,是零是吧,大家先记住这个事儿啊好诶这块呢,说到这个数组和对象呢,可能永远不会在这个占上分配啊,主要呢,就是都放在这个堆里边啊,先认可这个事,后边我们再谈一些高级的内容啊。呃,因为呢,战争中保存着保存的这个引用,这个引用呢,指向了对象或数组通在对中的实际位置,这个大家应该不陌生啊,就是咱们在战当中是不是讲过这个战争是吧,战争里边呢,是不是讲过叫局部变量表。
08:06
哎,就变量表里边咱们保存了,要么呢是基本数类型,要么呢咱们还可以存储,是不是这些引用这个对象的是不是这些引用啊。哎,没问题是吧,那你实打实的那个对象放哪了呢?哎,实打实的那个对象呢,放到堆里面。哎,这个大家先看我这样的一个图吧。啊,一个简图啊,哎,这是一个站。啊,这个站啊,这个站里边啊,咱们对应的两变量啊,这个这个图对应的这个代码是在这个啊,咱把这个代码也打开。哎,Simple c啊,把它打开啊,那这里边呢,你看这是一个类啊,这是一个属性构造器,一个方法,主要呢,我们看这个main方法,这个main方法呢,我要一执行,这呢是我们的一个主线程呗,主线程,主线程里边一个方法,哎,那么那方法中我们造了俩对象啊,这两对象呢,S1S2,哎方法。你看这块呢,提到咱们这个叫主线程是吧,主线程这个线程里边呢,咱们有个战针,这就是你这个没方法的这个战争,这个一个战针里边我们说有一个局部变量表。
09:03
还记得吧,咱们前面讲过,聚变量表里边维护了一个叫S1,一个叫S2啊,放了这俩变量啊,一个S1,一个S2。行,那么因为呢,你是对象嘛,所以这里边我们放的是不是实际上是不是就引形地址啊,那这两个引形地址呃,真正指向的那个对象在哪呢?咱们说堆一里边是负责创建对象的,哎,他就扭了俩对象有他们各自的这个首地址值,S1呢指过来,S2呢指过来。对吧,哎,是这样的一个场景,哎,也就是我们这里边儿所描述的这样一个场景。哎,在这个站里边,咱们放的都是这个所谓的哎,引用类型变量的地址值堆里边呢,放你实打实的这个对象实体。所以这个对空键呢,它要求是不是较大一些啊,那么你这个对象实体所属的类是什么呀?啊,你的这个定义的这些结构方法都在哪呢?我们这儿呢,又提到这个叫方法区啊,提到了这个类本身类的结构,还有这个常量值。啊,这个咱们到下一章再讲的一个方法区啊好这呢就是我们讲的这叫占堆方法区这样的一个关系式。
10:04
哎,这个大家呢,去体会一下啊行,然后下边有提到说在在这个方法结束以后。哎,在这个方法结束以后啊,咱们堆中的这个对象啊,不会马上被移除,仅仅是在这个垃圾收集的时候呢,才会被移除。这个大家要理解啊,你要你要清楚,也就是说呢,咱们这个站里边啊,就比如说咱们还以刚才说这个没方法为例啊,哎,这两行代码咱们先给它注释一下。哎,先不要了是吧,哎,我们这两行代码执行完以后呢,整个这个may方法呢,你看是不是就执行结束了,May方法执行结束的时候呢,咱们这个may就是这个主线程是吧,这个me的这个战争啊,在这里边呢,有一个S1S2这两个这个这个变量是不是就出战了。哎,我们叫弹出站啊,S1S2呢,他俩就出站了,他俩出站以后,咱们堆空间中,你一开始是不是有这个引用地址啊,那你这两个引用的指针是不是就干掉了,因为这两个变量已经出站了啊,那这两个引用指针没有了,那我们对空间中这两个对象呢,实际上啊,就认为是垃圾了。
11:09
啊,就认为是垃圾了,但是这时候认为是垃圾这个事儿呢,哎,是要等到咱们这个JC的时候,咱们进行判断,一判断呢,说你俩呢,没有地址了是吧,没有引用了啊你俩是垃圾了,就是在我们这俩出战的时候呢,他俩还这时候没有判断是不是垃圾。啊,就是并不是咱们这个这俩这个大家一定要清楚啊,很多这个,呃一一些老师讲课的时候呢,这个就是一个错误的说法啊,说呢,我们这个站里边这俩变量一弹出战,说这个对攻间的这俩对象呢,也被回收掉了,不是一些,呃,就是这个一发生这个马上就连锁的发生了,不是这样子的啊。啊,应该是什么样子啊,就是这两个变量,你走了以后,咱们这个堆空间。你该放还放是吧,你该放还放啊,等到我们这个堆空间呢,你相应的这个空间不足了,这个时候呢,我们要JC了,要垃圾回收了,只有一回收发现,哎,你俩呀,不靠谱啊,没有指针指过来,所以你俩是垃圾,我要回收你们是吧?哎,这个时候才回收的。
12:10
啊,这要注意啊,不是说这块一出来这个就立马回收了,那为什么不说这个一走这个马上回收啊,那你想想如果要是这样的话呢,咱们这个站里边这个方法啊,是不是诶被调用的这个概率很高啊,那如果说这个里边的局部变量表都指向了是我们这个堆空间中的这个对象的话,如果都有这样指针的话呢,你像这块呢,如果一走弹出站这个呢,垃圾回收,那意味着咱们这个堆空间中这个GC的频率是不是特别高啊。频率高怎么着啊,是不是就影响咱们这个用户线程去执行啊,因为这呢又提到了一个就是呃,Stop word的一个问题啊,就是用户线程跟我们这个垃圾回收的线程,他俩能不能并发执行的问题。啊,那很多时候呢,我们说这用户线程,呃,跟这个垃圾回收线程,垃圾回收的时候呢,其实我们需要用户线场去进行一个solve world是吧,你先停止一下,那你要老老是垃圾回收,你像用户现场是不是就会很大程度上受影响,那我们这个程序是执行是不是太慢了。
13:06
对吧。哎,所以我们不能老是让它执行JC啊,就当你满不满的时候,我们再执行JC是吧,应该是这样子的啊,哎,所以呢,我们其实呢,很多时候呢,是把这个对空间比如花的大一点,或者我们这个合理的分配一下,呃,尽量减少这个JC的次数,然后这样的用户现场执行的是不是就时间更长一点,是不是就提到一个优化的一个目的啊。对吧,哎,就是这样个原因啊,行这呢,先明确我们刚才说的这个问题。啊,就是哎,垃圾回收的时候呢,我们对空间中的那个对象啊,才会被回收掉啊行,那么刚才呢,上边是不是也提到个对象创建啊,咱们看了这个例子,哎,把这两个代码呢,咱们也打开。关于对象创建这块呢,大家还可以有一个更深刻的一个理解,哎,我们把这个程序呢,先做一个。啊,变异是吧。嗯,可以了,那编译完以后呢,咱们再用一下这个工具,这个工具呢,咱们前面也给大家讲过,就是这个接class lab,你可以在我们这个设置这块。
14:02
那这不有这个插件吗。哎,Plugins啊,大家在这块呢,可以去搜索一下咱们这个接class lab啊行,把它装一下就行啊,那么装完以后的话呢,我们选中当前这个类,直接在这块呢,点这个view有一个叫诶with接class,点开这呢,就我们看一下这个诶自解码的一个反编译是或者我们也称为叫反解析也行啊呃,这个结构里边我们主要来看这个方法里边这个main方法啊,打开这个code啊,大家来看一下。那么这个程序的话呢,嗯,针对于我们前两行代码呢,是造了俩对象,这两个对象的话呢,我们用的这个new关键字,在我们底层这块呢,对应的这个字节码指令呢,也是这个new,哎,就是这两个new,那造的都是这俩对象是吧?然后在后边这两个数组的话呢,我们对应的这个哎字节码虽然叫主级符也行啊,叫new a啊,这叫new arra,哎,这两个结构一个呢是in型的数组,一个是object型的数组。好,这呢,我框住的这四个篮框,就是我们,哎创建对象的这个指令。New,哎,当我们一旦执行这个new的时候。
15:03
哎,就会在我们这个堆空间当中去创建对象。就在我们这个对空间当中去创建对象,而且呢开辟空间。哎,就开辟空间了,这就这个我们这个new做的这个事儿啊,那么接下来你干什么呀,接下来咱们这个GM是不是还需要呢,在这个对空间当中给我们去,呃,初始化你这个,呃,这个对象的一些实例变量啊。是吧,哎,就是从咱们这个代码上来看的话呢,非常简洁,就一个拗就能搞定,实际上在我们这个堆里边做的事很多。啊,所以呢,这也是我们这个对空间中我们要考虑优化的一个原因是吧。好,那这呢是我们说这个new啊,创建对象的这个问题啊,那么垃圾回收呢,刚才也提到了这个对象呢,不是说哎这两个一出站马上回收好已经过了啊,然后再看看,最后说这个堆是咱们这个GC啊有垃圾回收的一个重点区域。堆是垃圾回收的重点区域,为啥呢?因为咱们站里边,咱站里边有垃圾回收吗?
16:02
就咱们讲这个迅击战的时候。哎,那要面试问的,你这个说站里边有垃圾回收吗?是不是一定要说没有啊。哎,站里边没有JC啊,咱们站的话呢,是不是只有入站和出站操作啊,出站了相当于自动的就结束了是吧?哎,垃圾回收呢,我们主要指的其实就是对当然呢,这个方法区呢,也存在着垃圾回收啊,主要的操作呢,就是这个堆空间。啊嗯,为什么说这个堆咱们重点要强调它的这个垃圾回收啊,是这样子的哈,因为这个,呃,在这些的时候呢,我们主要考虑的是这个堆空间来回收这个堆象,包括这个数组是吧,当你要是有这种大对象大内存的时候啊,大内存的一个调用啊,你像这里边分配了很多空间,有些没有用了,我们要回收,那这个时候呢,频繁的进行一个回收,哎,我们就需要考虑怎么去提升性能啊,因为这时候频繁的刚才提到了频繁的这个JC是不是会影响我们这个用户线上的一个执行。对吧,哎,当然我们希望用户线能执行的是不是越多越越快,吞吐量是不是就越大啊这些呢会影响这个回收,再者呢,就是说内存分配的要是不合理的话呢,是不是也可能会报相应的一些异常。
17:03
哎,这是我们要注意的问题。啊,也就是说呢,这个JC在咱们这个大内存啊,以及呢,这个比较频繁的。拼拼怎么写?哎,在我们大内存和频繁的JC环节当中啊,它会成为咱们性能的一些瓶颈,所以我们这个,呃,重点要谈这个JC,重点呢要关注这个堆,诶所以从这个角度来讲,这个堆呢,是我们整个这个内存结构中最重要的一个结构呢,哎,我们这样说是不为过的。好,这呢就是我们关于这个堆的一个概述啊。
我来说两句