》哎,今天被面试官虐了,一直问垃圾回收的问题,开始能回答几个问题,后来就答不上来了以后再忍吧。”刚刚面试完,小程走进洗手间,在电话里跟朋友诉苦。》一开始从JVM上问我关于Java堆的内存划分,后来问我为什么要把新生代分老年代,哪些对象会被认为是垃圾,垃圾的RootSets是什么“收藏。你说我们都背年轻一代,记住伊甸园、幸存者等等……”听到小程的抱怨,正在打扫厕所地板的老爷子手里的拖把慢慢慢了下来。老爷子见小程挂了电话还一副“义愤填膺”的样子,就过来聊了起来。“小伙子,你还在死记硬背,看来你还没有理解Java的垃圾回收。”“哟,你也懂Java?”小程惊讶地看着老人,虽然他经常看到老人打扫厕所,但还是第一次知道他也懂编程。“说实话,我以前做过开发。”老人一边说着,一边看着窗外,仿佛想起了往日的岁月。“那你为什么不晚点做?”“老头子~”萧程的几句话,把老头子拉回了现实。“嘿嘿,有机会再和你聊聊,今天我大概跟你说说我对Java垃圾回收的理解,看看对你有没有帮助。”“好的。”小程半信半疑。伴随着厕所里空气清新剂的味道,老人深吸一口气,开口说道。“就拿我每天打扫的厕所来说吧。Java中一般的“堆”内存不就是分成几个“代”的吗,对象内存分配尽量在年轻代做。”听专业词汇“堆”和“晚辈”,小程连忙点头,感觉自己真的听懂了。“其实对象内存的分配和垃圾的收集并不是独立的,回收空间的方式也会影响分配的方式。”“而这一切都是为了效率,类似于我们平时的清理工作,会一直很忙,效率还是很差。比如在Java的垃圾回收过程中,为了不让新的内存分配影响到现有的垃圾回收工作,就会出现Stop-The-World.在这段时间里,为了垃圾回收工作,分配对象的线程必须停止。”“我们的打扫就像一个垃圾回收线程,而你的马桶就像一个分配内存的线程。”你应该有这样的印象,为了尽快把马桶打扫干净供你使用,有时候我们的打扫会放一个厕所门上的小牌子,“正在打扫,请勿使用”。没错,这就是我们的STW。如果你不进来“闹事”,我们可以快速收拾地面,清理水槽,以后你可以愉快地使用它。”“然后每次都放个牌子,大家匆忙用起来不方便。”小程已经进入了这个生活场景。“是的,所以在大家经常使用的早上和中午,我们虽然在打扫,但不能放牌子。我会在这个时候打扫用过的水池,因为我可以一目了然看到使用过的池,就像第一步的垃圾标记。清理的时候,不会影响大家对其他池的使用,就像垃圾回收CMS的并行执行一样。”为了进一步完善每个人上厕所的效率,我们也分配了几代人上厕所。左排是大手,像老一代,右排是小手,像年轻一代。这样大对象直接分配给手大的老年代,耗时较长,“短操作”直接在右边快速解决,快速离开。我们也可以把做空操作的区域分成两半。我在中间放了一个标志以确保分配。永远是一个连续的空间,用完一半再打开另一半。”“如果小手解了一半,想玩大的,请往左走。当然,你说的在年轻代使用的“复制算法”在这里有点不适用。不可能是闺蜜。过程进行到一半的时候,我说,朋友,你挪到边上那个,我来擦这个。他不得不打我。“”标记去除是最常用的。通常,在工作时间,我们会手动标记用过的小便器,或者记下来,或者在上面做一个标记,然后我们会立即清洗。”“标记-清洗类似。比如我们经常会找一条线来分隔几个池子。使用时,先用这一面。我会清理那边的脏东西。让一切离开。也许这就是为什么你没有一个很好的类比。不然你就觉得有个哥们小便几次就需要换地方,所以他需要几个连续的水池,那我就得打扫一个干净一个脏,不连续的,给他们用””“少爷,我现在有点乱”,听着老爷子说了一大堆内容,小程时而明白,时而迷茫。“来,我再给你一刀。””看,首先,你要记住最重要的一点,不同的垃圾回收方式也决定了内存的分配方式,这两者并不是独立的。同时,为了更高效的完成工作,通常是结合几种回收方式,比如年轻代这里一般使用“复制算法”,因为一般对象的生命周期毕竟不长,同时只复制标记存活的对象直接走就行了,复制完之后,空间还是连续的,多好啊。剩下的可以直接清空。所以在新生代复制几轮之后,该清空的都清空了。剩下的就清零了。转移到老一代。””在老年代回收的过程中,难免会把这个对象清除掉,但是旁边还占着呢。那么下次年轻代来个大家伙,或者年轻代来两个对象。“夫妻,人要挨着坐,坐不下怎么办?所以我得把这些不连续的空间整理一下,剩下的都整齐排列,其他的地方给新来的人腾出来,这时候就要用到我们所说的“标记-排序””“所以你应该发现了即不同的垃圾回收算法,因为要做不同的事情,所以花费的时间也不同。对于高吞吐量和低延迟,您不能同时拥有两者。只能称重。所以你发现有些站台等,人少的时候可能会锁几个,或者画一条线,标示只能使用某些部分,这样可以减少回收的时间。”时间长了,哪些是垃圾?我们平时开门看看谁在用,我们会偷偷记住,凡是用过的“痕迹”都算垃圾。门是整个寻找的“根”,各层厕所的门就是我们寻找“垃圾”的“根”。垃圾回收中不是也叫“寻根算法”或者“可达性分析”吗?从“根”开始搜索,一直向下搜索。那些可以链接到的对象称为可达对象。他们幸存下来,没有人用过垃圾。在Java中,被“虚拟机栈和本地方法栈”引用的对象,被静态属性引用的对象和常量被视为“厕所的门”。“像一些小厕所,我们可以自己打扫。在车站、机场这样大的地方,一个人是打不干净的。为了更快打扫干净,会同时出动几个清洁工。这是就像垃圾回收中的并行收集器,多个线程协同工作使其更快。”哦,对了,垃圾回收还有一个“安全点”的概念,就是只有在这里执行垃圾回收,才不会出现错误。为什么呢?主要是为了让根集枚举garbagecollection更准确,准确的说,编译器可以为每条指令记录一些信息,在需要STW的时候使用,但是如果每条都记录,成本太高,所以选择了一小部分,这是一个安全点,如果把厕所里的某个时刻当做一个可以暂停的点,即女清洁需要清洁男厕所,此时需要观察询问里面是否有人等到安全了,就开始打扫了,大家先“停止使用”,看到几个家伙走进厕所,“有时间再说吧”,老头连忙开始挥舞拖把和往常一样,认真地开始了“垃圾收集”。
