3. 常用的垃圾收集算法
Posted li-jing
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3. 常用的垃圾收集算法相关的知识,希望对你有一定的参考价值。
3.1 标记-清除算法(Mark-Sweep)
标记-清除算法从根集合(GC ROOTS)进行扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未被标记的对象,进行回收。标记清除算法不需要进行对象的移动,只需对不存活的对象进行处理,在存活对象比较多的情况极为高效,但由于标记-清除算法直接回收不存活的对象,因此会造成内存碎片。
3.2 复制算法(copying)
复制算法的提出是为了克服句柄的开销和解决内存碎片的问题。它开始时把堆分成一个对象面和多个空闲面,程序从对象面为对象分配空间,当对象满了,基于copying算法的垃圾收集就是从根集合中扫描活动对象,并将每个活动对象复制到空闲面(使得活动对象所占的内存之间没有空闲洞)。
3.3 标记-整理算法(Mark-compact)
标记挣了算法采用标记-清除算法一样的方式进行对象的标记,但在清除时不同,在回收不存活的对象占用的空间后,会将所有活动对象往左端空闲空间移动,并更新对应的指针。标记-整理算法是在标记-清除算法的基础上,又进行了对象的移动,因此成本更高,但是解决了内存碎片的问题。
3.4 分代收集算法
分代收集算法是目前大部分jvm的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation),在堆区之外还有一个代就是永久代(Permanet Generation)。老年代的特点是每次垃圾收集时只有少量对象需要被回收,而新生代的特点是每次垃圾回收时都有大量的对象需要被回收,那么就可以根据不同代的特点采取最合适的收集算法。
3.4.1 年轻代的回收算法(回收主要以copying为主)
1)所有新生的对象首先都是放在年轻代的,年轻代的目标就是尽可能快速的收集那些生命周期短的对象;
2)新生代内存按照8:1:1的比例分为Eden区和两个survivor(survivor0,survivor1)区。大部分对象在Eden区中生成。回收时先将Eden区存活的对象复制到一个Survivor0区,然后清空Eden区,当这个Survivor0区也放满了时,则将Eden区和Survivor0区存活的对象复制到另一个Survivor1区,然后清空Eden区和这个Survivor0区,此时Survivor0区是空的,然后将survivor0区和Survivor1区交换,即保持Survivor1区为空,如此往复。
3)当Survivor1区不足存放Eden区和Survivor0区存活的对象时,就将存活对象直接存放到老年代。若是老年代也满了就会触发一次Full GC(Major GC),也就是新生代、老年代都进行回收。
4)新生代发生的GC也叫做Minor GC,Minor GC发生频率比较高(不一定等Eden区满了才触发)
3.4.2 老年代(old Generation)的回收算法(回收主要以Mark-Compact为主)
1)在年轻代经历了N次垃圾回收然后让然存活的对象,就会被放到老年代。因此可以认为老年代中存放的都是生命周期比较长的对象;
2)内存比新生代也大很多(大概比例是1:2),当老年代内存满时触发Major GC即Full GC,Full GC发生频率比较低,老年代对象存活时间比较长,存活率标记高。
3.4.3 持久代(Permanet Generation)的回收算法
用于存放静态文件,如java类,方法等。持久代堆垃圾回收没有明显影响,但是有些应用可能动态生成或调用一些class,例如Hibernate等,这时候需要设置一个比较大的持久代空间存放这些运行过程中新增的类,持久代也称方法区。
以上是关于3. 常用的垃圾收集算法的主要内容,如果未能解决你的问题,请参考以下文章