JVM中垃圾回收相关算法 - 我想是值得你了解一下的,因为早晚得了解。😁 概要:当成功区分出内存中存活对象和死亡对象后,GC接下来的任务就是执行垃圾回收,释放掉无用对象所占用的内存空间,以便有足够的可用内存空间为新对象分配内存。目前在JVM中比较常见的三种垃圾收集算法是:标记一清除算法(Mark-Sweep)复制算法(copying)标记-压缩算法(Mark-Compact)
地点:
湖南省永州市蓝山县舜河村
作者:
用心笑*😀
标记-清扫式垃圾回收器是一种直接的全面停顿算法。简单的说,它们找出所有不可达的对象,并将它们放入空闲列表Free。
标记的过程其实就是,遍历所有的GC Roots,然后将所有GC Roots可达的对象标记为存活的对象。
如下图:
清除的时候将遍历堆中所有的对象,将没有标记到的对象全部给清理掉
这里所谓的清除并不是真的置空,而是把需要清除的对象地址保存在空闲的地址列表里。下次有新对象需要加载时,判断垃圾的位置空间是否够,如果够,就存放覆盖原有的地址。
优点:优点就是简单理解,容易实现。内存消耗较小。
缺点:1)不管标记还是没有标记,都需要进行整体扫描一遍,效率低;2) 进行GC 时,会停止用户程序,并且时间开销大,对用户体验较差;3)垃圾回收清理出来的空间内存,内存可能是不连续的,这就可能会产生内碎片(操作系统方面知识),就需要再维护一个空列表。
为了解决标记 - 清除算法在垃圾收集效率方而的缺陷M.L.Minsky于1963 年发表了著名的论文, “ 使用双存储区的Lisp语言垃圾收集器CA LISP Garbage CoIIector Algorithm Using SeriaI Secondary Storage 。M.L.Minsky 在该论文中描述的算法被人们称为复制(copying) 算法, 它也被M.L.Minsky 本人成功地引入到了Lisp语言的一个实现版本中。
GC复制算法原理是把内存分为两个空间一个是From空间,一个是To空间,对象一开始只在From空间分配,To空间是空闲的。GC时把存活的对象从From空间复制粘贴到To空间,之后把To空间变成新的From空间,原来的From空间变成To空间。回收前后对比下图所示
应用场景:目前JVM大都使用在新生代的垃圾回收中。
对于任意的GC算法我们都可以从吞吐量(GC延迟),内存的分配效率,内存碎片化,堆的使用效率这个几个方面评估。
复制算法还有一个情况:如果系统中的垃圾对象很多,复制算法需要复制的存活对象数量并不会太大,或者说非常低才行(老年代大量的对象存活,那么复制的对象将会有很多,效率会很低),所以复制算法大都是应用在新生代中的垃圾回收。
复制算法的高效性是建立在存活对象少、垃圾对象多的前提下的,这种情况在新生代经常发生,老年代很难出现这种情况。
标记一清除算法的确可以应用在老年代中,但是该算法不仅执行效率低下,而且在执行完内存回收后还会产生内存碎片,所以JVM的设计者认为前两种都有问题,即提出了第三种垃圾收集算法:标记-整理算法,可以说是整合了前两种的优势。
前面标记部分同标记清除部分,不同的地方在于,标记清除中只是把可回收的对象进行垃圾回收,不会对剩余的内存空间进行整理,而标记整理则会对存活的对象进行整理,截图对比如下所示:
标记-压缩算法的最终效果等同于标记-清除算法执行完成后,再进行一次内存碎片整理,因此,也可以把它称为标记-清除-压缩(Mark-Sweep-Compact)算法。
二者的本质差异在于标记-清除算法是一种非移动式的回收算法,标记-压缩是移动式的。是否移动回收后的存活对象是一项优缺点并存的风险决策。可以看到,标记的存活对象将会被整理,按照内存地址依次排列,而未被标记的内存会被清理掉。如此一来,当我们需要给新对象分配内存时,JVM只需要持有一个内存的起始地址即可,这比维护一个空闲列表显然少了许多开销。
优点: 则是一定程度上解决了前两种算法的缺陷,1)消除了标记-清除算法当中,内存区域分散的缺点;2)不用像复制算法一样,内存减半的高额代价。
缺点:
1)从效率上讲,是不如复制算法的。
2)移动对象的同时,如果对象被其他对象引用,则还需要调整引用的地址
3)移动过程中,需要全程暂停用户应用程序。
标记清除 | 标记整理 | 复制 | |
---|---|---|---|
速率 | 中等 | 最慢 | 最快 |
空间开销 | 少(但会堆积碎片) | 少(不堆积碎片) | 通常需要活对象的2倍空间(不堆积碎片) |
移动对象 | 否 | 是 | 是 |
结论:没有最好的算法,只有最合适的算法。(不然那还有这么多算法的存在勒)
堆部分中年轻代是是使用标记-复制算法进行垃圾回收,主要是因为年轻代里的对象存活时间比较短,大都朝生夕死,一次可以清除大部分对象,这样只需要把少数对象移到另一块内存中去,效率很高。
但是在老年代中,就不一样了,老年代老年代,你一听就知道这里面对象的存活时间很长,而且大多数对象都会活很久,如果使用复制算法,每次清除的对象很少,需要移动的对象很多,效率很低。那么使用标记-整理或者标记-清除更加合适,效率也会比较高。
每天的生活,慢慢变的充实,未来很长,我们一起努力!!!