91名师指路-头部
91名师指路

JVM系列(十二):GC算法:引用计数,复制,标记清除,标记整理

由于某些原因,现在不支持支付宝支付,如需要购买源码请加博主微信进行购买,微信号:13248254750

一:引用计数。


二:复制算法。

2.1 年轻代中使用的是minor GC,minor GC采用的是复制算法。

2.2 HotSpot JVM把年轻代分为了三部分:1个Eden区和2个Survivor区(分别叫from和to)。默认比例为8:1:1,一般情况下,新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC后,如果仍然存活,将会被移到 Survivor区。对象在Survivor区中每熬过一次 Minor GC,年龄就会增加1岁,当它的年龄增加到一定程度时,就会被移动到年老代中。因为年轻代中的对象基本都是朝生夕死的(90%以上),所以在年轻代的垃圾回收算法使用的是复制算法,复制算法的基本思想就是将内存分为两块,每次只用其中一块,当这一块内存用完,就将还活着的对象复制到另外一块上面。复制算法不会产生内存碎片。

2.3 复制算法的优点:不会产生碎片。

2.4 复制算法的缺点:浪费内存空间。它浪费了一半的内存,这太要命了。如果对象的存活率很高,我们可以极端一点,假设是100%存活,那么我们需要将所有对象都复制一遍,并将所有引用地址重置一遍。复制这一工作所花费的时间,在对象存活率达到一定程度时,将会变的不可忽视。所以从以上描述不难看出,复制算法要想使用,最起码对象的存活率要非常低才行,而且最重要的是,我们必须要克服50%内存的浪费。


三: 标记清除法(Mark-Sween)  。

3.1 标记清除算法:分成标记和清除两个阶段,先标记出要回收的对象,然后统一回收这些对象。用通俗的话解释一下标记清除算法,就是当程序运行期间,若可以使用的内存被耗尽的时候,GC线程就会被触发并将程序暂停,随后将要回收的对象标记一遍,最终统一回收这些对象,完成标记清理工作接下来便让应用程序恢复运行。

3.2 老年代一般是由标记清除或是标记清除与标记整理的混合实现。

3.3 标记清除算法的优点:相比于复制算法不需要额外的空间。

3.4 标记清除算法的缺点:1 效率比较低(扫描两次,一次标记,一次清除)。2 产生内存碎片。首先,它的缺点就是效率比较低(递归与全堆对象遍历),而且在进行GC的时候,需要停止应用程序,这会导致用户体验非常差劲;其次,主要的缺点则是这种方式清理出来的空闲内存是不连续的,这点不难理解,我们的死亡对象都是随即的出现在内存的各个角落的,现在把它们清除之后,内存的布局自然会乱七八糟。而为了应付这一点,JVM就不得不维持一个内存的空闲列表,这又是一种开销。而且在分配数组对象的时候,寻找连续的内存空间会不太好找。


四:标记整理。

4.1 标记整理优点:不会产生内存碎片。

4.2 标记整理缺点:效率不高。(不仅要标记所有存活对象,还要整理所有存活对象的引用地址)。在整理压缩阶段,不再对标记的对像做回收,而是通过所有存活对像都向一端移动,然后直接清除边界以外的内存。可以看到,标记的存活对象将会被整理,按照内存地址依次排列,而未被标记的内存会被清理掉。如此一来,当我们需要给新对象分配内存时,JVM只需要持有一个内存的起始地址即可,这比维护一个空闲列表显然少了许多开销。


五:哪一种算法最好?

答:没有最好的算法,只有最合适的算法,分代收集,年轻代用复制算法,老年代用标记清除或标记清除和标记整理配合使用。


六:总结

内存效率:复制算法 > 标记清除算法 > 标记整理算法(此处的效率只是简单的对比时间复杂度,实际情况不一定如此)
内存整齐度:复制算法 = 标记整理算法 > 标记清除算法。
内存利用率:标记整理算法 = 标记清除算法 > 复制算法。
可以看出,效率上来说,复制算法是当之无愧的老大,但是却浪费了太多内存,而为了尽量兼顾上面所提到的三个指标,标记/整理算法
相对来说更平滑一些,但效率上依然不尽如人意,它比复制算法多了一个标记的阶段,又比标记/清除多了一个整理内存的过程。


2020-03-30 16:48:43     阅读(1818)

名师出品,必属精品    https://www.91mszl.com

联系博主    
用户登录遮罩层
x

账号登录

91名师指路-底部