2021-05-28

GC垃圾回收

什么时候触发GC?

手动触发:当前程序去调用System.gc()的时候触发。注意:GC回收的时候程序会停止运行,同时回收的过程中,会消耗大量的系统性能,所以,一般情况下我们不会主动的去调用gc回收方法。

自动触发:根据Eden区和From Space区的内存大小来决定。当内存大小不足时,则会启动GC线程并停止应用线程,程序zaishenq内存的时候,系统(jvm)发现内存不足,这个时候就会触发GC.。

GC回收的算法?

标记清除

分为两个步骤,第一个步骤就是标记,也就是标记处所有需要回收的对象,标记完成后就进行统一的回收掉那些带有标记的对象。这种算法优点是简单,缺点是效率问题,还有一个最大的缺点是空间问题,标记清除之后会产生大量不连续的内存碎片,当程序在以后的运行过程中需要分配较大对象时无法找到足够的连续内存而造成内存空间浪费。

标记复制

复制将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另一块上面,然后再把以使用过的内存空间一次清理掉。这样使得每次都是对其中的一块进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况。只是这种算法的代价是将内存缩小为原来的一半。

标记整理

标记整理算法与标记清除算法很相似,但最显著的区别是:标记清除算法仅对不存活的对象进行处理,剩余存活对象不做任何处理,造成内存碎片;而标记整理算法不仅对不存活对象进行处理清除,还对剩余的存活对象进行整理,重新整理,因此其不会产生内存碎片。

分代收集

新生代->老年代->永久代

新生代:尽可能快速收集回收掉生命周期短的对象,一般情况下新创建的对象都放入新生代中。

老年代:老年代中对象的生命周期比较长。新生代经过N此回收以后,任然存活的对象。

永久代:主要用于存放静态文件,如:java类,方法。

在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法。只需要付出少量存活对象的复制成本就可以完成收集。

新生代中的对象如何向老年代过度?

1,新生代分为三个区域:eden,survivor0,survivor1三个区域,大量的对象都在eden区域,在gc的时候,先将eden区存活的对象复制到survivor0区域,然后清空了eden。当survivor0区域满了以后,则将eden和survivor0区域中存活的对象复制到survivor1区域。然后清空eden和survivor0区域。把survivor1中的数据全部复制到survivor0区域中。经过反复的gc,当survivor1区域不足以放下eden和survivor0区域中的存活对象,就直接将存活的对象放入到老年代。

2,老年代中因为对象存活率高,没有额外空间对他进行分配担保,就必须用标记-清除或者标记-整理。

注意:在jdk8的时候java废弃了永久代,但是并不意味着我们以上的结论失效,因为java提供了与永久代类似的叫做“元空间”的技术。

猜你喜欢

转载自blog.csdn.net/DikY_/article/details/117373044