00:00
好,同学们,接下来我们来看一下,上面我们已经讲过用弱引用回答了为什么要用弱引用,那么下面我们的问题是用弱引用是不是就万事大吉了呢?答案是,还有一个小小的细节要注意面试和使用过程当中清楚原理,回答清楚,那接下来。我们都晓得这块强引用,这块弱引用,只要这个用完了,TL结束,只要是弱引用跟着走,对吧?就像我们刚才所说的,如果一个人正常的去世了,一个自然人,那么对应的他的身份证的这些信息也应该是不会被更新了,也应该被跟着走,被注销,这样的话腾出空间减少内存消耗,一一句话使用若引用就可以使所有的local对象在方法直接完毕后顺利被回收,且ENT key这个引用是指向那。好,那么如果你用这个N出的K就指向,那因为这哥们已经完了,我们前面已经说过这个被回收,那么相当于说这是不是就是个none了,对吧?那接下来我们的问题就来了。正因为这个ENT出key的引用指向,那就会有第二个雷,也就是现在本节我们要给大家讲的,因为这三个方法尝试删除key为难的N醇可以释放value对象所占用的内存,这是什么意思啊?好,那么同学们这三个方法底子有个共同之处来,同学们若引用不到,那么下面我们的问题是二号坑。
01:25
上面这个续,接下来我们大家都清楚。搁到这儿这个TL对吧,如果它是个。强引用,那么你晓得的底子是会留一些东西的,那么所以说我们希望它用完的时候回收,把若引用的一块带走,为什么要这么干?当我们为此local变量赋值啊,实际上就是往当前的N,说白了我们都清楚啊,就是往这个当前这个NT出s local map里面这个NT赋值是这么一个东西,把自己作为key丢进去。那么往这个local map当中存放N处以中的key是弱引药单local的外部强药。
02:03
为,那也就是说我现在把这个TL假设用完了,是为纳,那它是不是应该被回收啦?那么GC的时候,根据可达性分析,这个的local实力,就没有任何一条链路能够引用到,所以说这个local势必被回收,那么这样一来,也就是我这块假设是烂了,那么整个对象是不是被干掉了,被GC回收了,GCE回收了,我这块就变成了一个烂的一个。为难的一个空。J听懂,K就是个nu value还继续存在着,那这个就很可怕,那么所在的local当中就会出现K为难的entry,就没有办法访问这些key为难entry的value,如果当前线程再迟迟不结束,什么叫当前线程迟迟不结束?别忘了阿里巴巴手册,尤其是在线程制的场景下,现程经常会被什么服用,那么一被复用了,是不是就迟迟不能结束啊?那么这个时候。
03:01
如果仅仅使用弱饮用的话,是对的,99%没问题,但是就会存在很多key为nu的N醇value,就会一直存在一条强引用,某一个线程的引用实际的线程对象,那么我们这儿说过了什么线程经常会被复用,那么这些线程没回收,每个线程自己都有一个所local map,那相当于嘛,这个人没了什么身份证还在听到那么。Local map有entry,那么ENT这个value就永远无法回收,最终会导致内存泄露。好,那接下来。当然,如果当我们这个线程运行结束了,所local local map n没有引用链可达,那么在垃圾回收的时候,你就会被回收架不住,就是线程池里面这种线程副药。那么所以说。实际使用当中啊,我们基本现在多线程很少再去利用一个线程,都是线程去服用,去维护我们的线程,比如说我们这个我们都用过,那么为了复用线程。
04:02
这个呢,它不会结束,那么这样就会容易导致所有的logo内存泄露,就要值得我们小心,好那么接下来我们来看,所以说你一回烧。这块就是个K,你可别忘了啊,我们的哈希map大家都用过啊,哈希map.put假设我这随便乱写那123弟兄们最右边语法并没有报错,这种map是允许空值空间的,那么这个K就是一个难的时候,那么没有哪个线程的名字叫,那么都找不到,但是这个value有值呢,如果没有回收掉,大规模的就会在内存里面待着。相当于说有一大节车厢就存在内存里面,但是火车头是个烂,那么这不就越积越多,容易内存泄露,那么怎么办呢?所以说呢,我们这K为难的NT出。他呢,是这么干。首先。所以local使用。Thad local map使用ad local的弱引用,请看啊,Ad local map就是这个ENT对象,它这个T是使用local作为弱引用,如果TL就是ad local外部没有强引用引用它了,那么GC的时候这个所local就会被干掉,它就是个烂,这样一来local map当中就会出现key为nu的什吧建值,对entry这个是个nu value值还在,就没有办法访问这些K为nu的entry的value,如果还在线程池里面用,那么这些key为难的entry的value就会一直存在一条强引用链,那么这个时候没法回收啊。
05:36
一大截的车厢在这儿,火车头没了,越积越多,容易出事,所以呢,我们呢就来看。虽然如果你用保证了key指向的所有local对象能够被及时回收,OK,一回收,这个所有local没了,访问不到了,但是value还在,那么。这个呢是需要我们呢,用map当中就要调用get set,发现这个key的时候,才会去回收整个ENT和value,也就是说如果这一块也没了,也请你把这个也没有。
06:10
火车车头没了,火车车厢也拿掉,不要用不到的东西长期堆积在我们的内存里面,因此若引用不能100%的保证内存不泄露,我们要在不使用某个所local对象以后,手动调用方法来删除它。能跟上。OK,阿里手册写这一段底子是有很多基础知识的,尤其是在线池当中,不仅是内存泄漏的问题,因为线程池中的线程是重复使用的,前面我们已经说过,给大家演示过那个什么比before和阿塔那个对吧?意味着这个线程的map的对象也会被复用,如果我们不手动调用remove方法,那么我们后面的线程就有可能获取到上个线程遗留下来的value,造成bug,那么这个呢,我们绝对给大家演示过我们在这的时候啊,这个。我们在写的这个时候,嗯,在这儿同学们还有没有印象local第二个案例的时候,我们这儿是不是说过这个比夫和这个after加不加这个finally remove是有根本性区别的,OK,好,我们理论都讲清楚以后,那么接下来我们就要去来看一下底层的源代码,那么记住这么一个方法叫exchange style en。
07:27
这个是什么?清除扫除打扫的意思,这个是什么?废旧淘汰过期的意思,NT,那么说穿了就是清掉local里面的三。N垂,OK,那么就相当于说走吧,清除。三。N醇,好,那么下面圆满说话。首先先来看看我们的sat啊。搁到这儿,弟兄们都用过了,这个是个set,好,那么先来看这个start local里面,我们这儿这个set方法,走到这儿他会有一个处理,叫K等于难,好,那么来吧。
08:07
我们都清楚sat先说set方法,你不管怎么用啊,Key都是它走走走走走来这有个e.get得到这个K叫local这一行,你看这个get叫什么,得到当前的这个引用,OK,好,如果说。这个K等于钠,那么同学们请看,OK,如果这个K不为难走这个分值,如果这个K等于钠,就是我们的脏ENT,它会replace调用这么一个方法,而这个方法走走走走走,我们再去找什么。这块我们会找到。搁到这儿了以后,它底层会有一个clean sum slots,清除一些槽位,又搁到这儿,请看调用这个方法走走走走走,大家请看有个什么,如果K等于烂的话,它会连带着这个K啊,请大家看,就是我们的所local,假设我们现在这个local已经用完,要被回收制为难了,那么这个时候请看你这个T就是nu s local就是难,这个1.value也会被置为难。
09:14
OK,好,那么所以说兄弟们挨个挨个找下来,那么无独有偶get呢,我们不妨呢也来看看我们这儿是个get,好那么。我们这get假设啊,它这个不为难或者是什么的,那么get ENT after Miss也进来,大家请看,如果说它等于难的话,也是调用这个方法。OK,你看get en after Miss嘛,好,点到这儿来,是不是跟刚才一样,T等于一捺的时候,e.value也给它制成了,所以说在这我们就get s get get,这个全带大家找了一遍,好,第三个我们最经典的remove来吧,兄弟们直接二话不说,只要不等于那的话,直接remove this,我点remove来可令,OK,然后完了以后你看我们先看看这个可令。
10:11
干嘛,是不是把这个以用之为难啊,OK,好,那么接下来再看原码分析,搁到这儿又碰不上这个方法,那么说穿了,这个K等于none的话,又把这个1.value也等于钠,那么这个时候就会让我们实现一种什么,那那那么这样的话,就是把没有火车头的这一些车厢这个value值。也给你干成了听懂,那么所以说全部下来了以后,三个方法都带大家认认真真的看完,所以说一句话,寻找3EN垂GK等于nu的en,然后进行什么删除啊,哎,彻底解决。这个内存泄露问题,所以说搁到这儿,我们可以看出三个方法。在整个所有的local生命周期里面,针对所有的local存在的内存泄露问题,做了一个什么补充,都用这个方法,然后呢,清理掉key为难的脏N垂,就这个意思,OK,好,所以说兄弟们,那么搁到这了以后,我们呢,得到的结论就是这么一个,所以说穿了到最后就是要用remove,因为我们大部分都是在线程池下面用,存在着线程复用,线程复用一定要就是用这个remove调用这个。
11:24
方法,清除掉key为难的脏entry OK,所以说所有的local内存泄露问题两个,第一个要用弱引用,第二个会清除脏N醇,这个就是我们最重要的结论,好,那么来看看,那么最后啊,我们接下来要给大家说的一些总结和最佳实践。
我来说两句