00:00
接着咱们来看第二个问题,诶第二个问题呢,叫做内存溢出与内存泄露,那这两个问题的话呢,其实对于大家呢,已经有开发经验的同意来讲的话呢,应该是都很熟悉的啊,所以这块呢,我们这个来给大家呢介绍一下这个概念就可以了,那首先呢,我们来看一下,这叫内存溢出啊,内存溢出我们主要呢回收垃圾呢,是针对于堆空间的,对吧?那当然咱们说这个站空间呢,也也可以叫溢出,叫stack overflow对吧?那当然这块我们更多关注呢,还都是这个堆空间啊,因为站空间呢,轻易呢咱们说不会出现这个溢出的问题,OK,那么这个堆于要是溢出的话呢,就是我们所谓的叫auto memory了啊,所以这块呢,所以内存溢出呢,我们就直接呢称为叫啊OMOK,那么内存溢出啊,我们说是相对于内存泄露来说的啊,尽管呢更容易被理解,但是同样的呢,内存溢出也是引发程序崩溃的叫罪魁祸首之一,那我们可能会由一些异常,比如说你是控制人呐,呃,脚步越界呀,类型转换错误啊等等这样的一些异常呢,会导致我们的程序呢崩溃对吧?当然还有一类问题,就是我们代码呢看呢都没有问题。
01:01
但是呢,由于我们这个内存空间不够啊,我们进行JC的时候呢,回收也没有及时呢,空出这个足够的空间,这时候呢,我们就报一个叫OM。啊,它呢是我们引起程序崩溃的叫罪魁祸首之一,对吧,那就需要呢,我们后期呢,进行一个呃,性能调优啊监控啊,通过监控呢,我们来进行这个调优。啊,那这时候我们就提到说这个不管你的这个工作年限有多长啊,技术实力有多强,那内存一出问题呢,都有可能悄悄的隐藏在你这个代码当中,对吧?你说这个控制帧呢,脚位月接啊等等这种情况呢,我们相对来说,当你经验多的时候呢,很容易发现啊,但是呢,我们说这个内存溢出问题呢,很多时候也并不是由于咱们这个代码呢,是有问题的,那跟你这个呃,程序的这个本身对空间的设置的大小呢也有关系,对吧?当我们呢,这个在程序运行起来以后呢,呃,程序一直执行发现呢,这个可以用的内存呢,越来越少。啊,甚至呢,呃,已经无法再为新的对象呢,再去分配空间的时候呢,那直接呢就报了一个OM,那这时候呢,就要引起我们的关注,我们要看一看是什么原因造成的,对吧?诶是这样的啊,那下边提到了说因为这个JC啊,一直在发展啊,也就是说呢,一般情况下呢,咱们不太容易出现这个OM啊,一般情下不太容易出现,因为我们这个JC的话呢,大家也会发现啊,当你如果去关注咱们JDK呢,不同版本迭代的话,你会发现呢,在每一个JDK的新版本当中的新特性里边,都多多少少会提到这个关于JC这块内容,也就是说呢,这个呃,Java虚拟机,我们或者说我们说叫JDK是吧,Java的语言呢,我们不断的去调节它的这个调优啊,这个让他这个程序呢,跑得更快,除了从这个语法层面呢,我们说去做一些改变之外呢,另外一个角度呢,就是我们不断的去优化这个底层的这个JC。
02:42
所以呢,到目前为止呢,我们其实呃,已经不是特别容易呢,出现这个OM这个情况了啊,但是呢,如果你这个应用程序当中发现呢,这个内存的一个占用速度呢,诶这个要高于咱们垃圾回收的这样的一个速度的话呢,那迟早呢也会出现OM,那主要呢,你就是关注一下,你看你这个应用程序的这个内存增长这个速度呢,是否是正常的对吧,是否是正常的啊,这个大家要注意行,那下边的话呢,就是说呃,我们在这个呃报这个OM之前,嗯,咱们在报这个OM之前呢,一定会进行一次这个独占式的for GC是吧,就是说我们垃圾回收了啊,这个要报OM了,说内存要移出了,那前提呢,我们先看一看,是不是我们进行GC之后呢,确实空间不够,呃,这个大家要注意一下这个行为对吧,那进行一次独占式的这个for GC,我们说这个呃,暂停时间呢,会稍微长一些,那通常呢,我们一般都会,诶这个释放出来一些内存供大家去使用,那如果这时候没有足够的内存,那就坏事了,那就OM了,对吧。
03:42
行,那在Java dog当中,我们对auto memory的error的这个解释呢,是这样子的,说呢,没有空闲的内存,并且呢,垃圾收集器呢,也无法提供更多的内存。哎,当然呢,你细细的体味一下,这实际上呢,说的是两个事儿对吧,一个呢就是空间不够了,另外呢,就是我JC之后呢,空间还不够,我们才会报这个OM。
04:04
哎,才会报这个外啊,其实这个呢,也有点像生活中的一个例子哈,呃,你像就以我为例吧,我的感触就挺深的哈,这个以前的时候呢,我还,呃就现在呢,这个这个有点经济基础了,买了一个房子是吧,在以前没有买房子的时候,或者说那刚买房子的时候,那时候也比较年轻嘛,对吧,诶将近30岁是吧?诶那时候就想着说,哎呀,哪个房子我想把家里边这个呃家具呢布得满满的啊,就是比如说呃,闲散的时候,这个把这个客厅上往客厅上随便一个位置一躺,哪怕坐地上整个地毯是吧?啊整点零食吃啊,特别的闲散,然后冰箱里边一定要放满这个可乐是吧?呃,要什么味儿的可乐都有啊,就是想的特别好,就把里把家里边装的满满的啊,这是一开始的时候那种想法哈,然后现在呢,我就不是这样想了啊,这个可能这个年龄大了也有关系啊,现在呢,我就想着说家里边呢,空间还是得稍微宽敞一点是吧,规规矩矩的啊,干干净净的简洁一些是吧,哎,就想的是这样啊,然后呢,你这个客厅里边呢,还是呃,放个桌子桌子。
05:04
字也别太大了是吧,呃,这个沙发呢,也别整太大的,整个还是这个空间呢,要要大一点的啊,别整的特别充实啊,这是我现在的特别的感,这个特别明显的一个感触啊,但是呢,由于现在呢,屋子里边已经整得很满了,所以这就很尴尬,有的时候呢,看到呃,一个小东西啊,一个小的装饰品也好,还是一个比较小小的一个家具也好啊,有时候我们在那个抖音上哪上面也能看到一些特别特别好的一些那个那个家具是吧?啊这个低的时候呢,能是个小桌啊,小孩子也能玩,然后呢,这个把他拉起来呢,她还能当一个餐桌啊,不用的时候平时还能收起来啊,这个空间占用非常小啊,我经常就跟我媳妇说说这个咱们要不买一个是吧,然后媳妇儿通常都说,说你看家里边哪有地儿了啊,那就相当于说,哎,你看没有空间空余空间了,那这是我说,哎,咱们收拾收拾,把家里边呃什么东西倒腾倒腾,咱们能不能空出来空间呢?那他说这个收拾收拾也盛不下啊,拾收也盛不下,你就别买了啊,就这个意思,那其实这里边呢,你看就蕴含了我们这两个点,第一个呢,说。
06:04
诶,我想买,他说你看家里没地儿了,对吧,这就说这个事儿,那我紧接着来一句,说那你收拾收拾是吧,咱们把家收拾收拾呢,不要了,咱就扔了啊,就垃圾收集一下是吧,收集完以后呢,看咱们能不能放得下啊,收集完以后也不行啊,那也不行,那没招了,那我就不能买了。那就不能买了是吧?哎,就成这个意思了,诶跟我们这两个行为呢,其实也是正好对应的啊行,那么接下来我们看下说所谓的这个没有空闲内存了啊,内存不够了啊,家里没地儿了啊,那这时候呢,是什么意思啊,哎,怎么造成的呢?我们这儿呢,有两个情况,第一个情况呢,就是你一开始设置这个堆内存啊,就是不够是吧,你家里边没地儿了,为啥你家太小了是吧,这买房子买太小啊,当然在北京的话呢,也咱也不可能买一个大房子啊,那个也不太现实,北京这个房价呢,还是比较夸张的是吧?行啊第一个问题就是说你这个堆空间你设置内存不够啊,这个原因,当然这里边所谓的内存不够啊,说也有可能会存在这个内存泄露问题,咱们呢,一会儿讲这个泄露,就是你内存泄漏的话呢,导致这个空间呢,总回收不了,说白了就跟你这个这个地儿就就就就已经确定好你不能用了是吧,就跟咱们说你买个房子80平,那80平里边呢,有十平它都是公摊,公摊你咋用用不了不让你随便占用这个公共的面积,对吧,但是里边呢,这公摊呢,就是有这一部分就恶心的这个事儿。
07:20
那这个公摊呢,就有点有点像我们这个泄漏一样,就是这块你回收还是回收不了,但是呢,它你也用不了啊,就是这样个情况。啊,然后呢,还有可能就是你设置这个对的大小呢,不太合适,那那这时候呢,你可以通过我们说前面讲过的这个啊,设置它的一个初始的一个对空间的大小和最大的对空间大小,我们呢,把这个对空间呢,设置成一个合适的一个值,对吧?诶这是这个问题,那第二个问题呢,就是你在代码中啊,创建了大量的大对象,那并且呢,这个长时间呢,不能被垃圾回收器所回收,哎,不能被回收呢,主要原因是因为我们这个引用呢,还是被占用着呢,对吧?我们通过可达性分析呢,发现你还是一个呃可触及的对象,那就回收不了,那是这样的一个问题啊这呢,我们举的这个例子呢,是针对于咱们说的这个方法区来讲的,那对于咱们以前的JDK这个八之前是吧,七的时候呢,我们还有这个叫永久带,咱们知道这永久带呢,它的默认的大小呢,是比较小的,那我们用于存放这个常量啊,还有这个类型,那我们对于这个方法区的垃圾回收,回收呢,咱们前面也都讲过了,主要呢,就是这个常量池的一个回收,还有这个呃,卸载不带被使用这个类,那卸载不带被使用这类这块呢,我们说还是挺复杂的啊123是吧,三个点都。
08:28
判断了还不一定能够回收,这个咱们前面都讲过,大家可以回去看看这个常量的这个回收呢,相对比较简单,跟对象一样,对吧,就可以回收,但是呢,由于我们这个云雾带的空间呢,它相对来说比较小,那你尤其是咱们说的这个,在我们需要呢,大量创建这个动态类型的这个场合,动态的加载很多的类,那导致呢,一下子把我们这个云用带呢,就承包了。啊,那甚至呢,还有这个我们去调离int方法,咱们前面讲string也说过了,对吧?诶调离int方法的时候呢,我们需要在这个常量池里边去分配这个呃空间,但是呢,你这个常量池里边这个空间的,呃,这个一开始的时候,在我们这个漆之前放的都是应用带是吧?应用带呢比较小,那放太多掉太多的应存方法,导致我们这个应用带呢就挂了,哎这呢报的叫OM啊叫space。
09:12
就是我们有应用带呢,哎,报了这样的一个OM了,那么随着我们这个使用这个原数据呢,咱们把这个相应的这个字符串场景池,包括这个静态的属性,我们都放在这个对空间当中了,呃,那原数据区呢,我们主要是放这个类型的这个信息,包括运是常量池中的其他的这个非阻串常量池的信息等等,呃,那么原数据区呢,它只是受咱们本地内存的一个上限的影响,那这时候呢,我们再报这个OM的机会呢,实实上要小很多,当然也不是说呢,不可能,咱们前面也给大家演示过,对吧?那这时候呢,报的OM呢,就叫Meta space,哎,这个情况OK啊,这呢是我们说针对你这个,呃,这个没有这个空闲内存的一个情况,我们说这呢,给大家举了个例子啊,两种场景,那么另外一个呢,就是提到。所以呢,我们在这个报OM之前,咱们刚才呢给大家也解释过了,他呢一定会去触发我们一次GC的。
10:04
就是你不能说呢,家里边儿有地儿吗?没地儿没地儿我就报OM,这不这也不行是吧,那你JC干什么了。GC怎么没起点作用呢?就是没地儿了,没地儿那咱JC一下,如果JC完以后呢,空间够了,那就用,哎JC完以后还不够,这时候咱们采OM,诶这个大家一定要明确对吧?行,那这时候呢,咱们这个要进行一次这个呃垃圾清除,呃垃圾清除这里边呢,就提到了,咱们一会儿呢给大家讲的这叫软饮用,那拉圾清除的时候呢,我们就会把这个软饮用呢再做一个回收,包括那个虚引用是吧,我们也会回收啊还有呢,在我们这个NIO当中,我们也会呢,底层去调这个c.JC总之呢,就是我们都要试图呢去清理一次垃圾,那如果清理了还不行,我们再报OM也不迟。啊是这样啊,然后这呢举了一个特殊情况,就呢,在一些特殊情况下呢,我们在报这个OM之前呢,说也有可能没有掉过垃圾收集器啊,没有进行过这个垃圾回收,什么情况呢?就是我们去分配一个超大的对象,这个对象呢,已经超过了咱们这个堆的最大值了。
11:05
对吧,就是你家呢,就只有80平,你说我现在需要放一个大的一个设备,这个设备呢,这个比你家这个房子还大,我这需要占一个100平,说你家里边收拾收拾,这不开玩笑嘛,你就是把这个家都搬空了,也盛不下,对吧,这时候就别收拾了啊,你这个超大,这个对象呢,已经超出了我们队的最大值了,这个时候呢,咱就别收拾了,直接就OM吧,告诉他不行是吧,挂了,哎,就是这个道理。行,这呢,就是咱们说的叫内存溢出的问题啊,那对于大家来讲,这呢应该是比较熟悉啊,那就这块我们做一个复习。
我来说两句