JVM的垃圾回收的算法
什么是垃圾
没有引用指向的任何对象
一、标记清除算法(Mark-Sweep)
标记清除算法是最基础的回收算法,该算法包括两个阶段:①标记阶段 ②清除阶段
标记阶段:根据可达性分析算法找出需要回收的对象进行标记。
清除阶段:统一回收被标记的对象.
该算法的优点和不足:
优点:
1.一目了然的就是逻辑简单,之后的算法也是在此基础上进行优化。
不足:
1.效率问题:标记和清理的效率都不高(第一次扫描标记不可回收对象–根可达标记为存活对象,第二遍清除没有被标记的对象)
2空间问题:清除的时候,只是将零散的存储在内存中的对象进行回收,没有进行整理,导致很多零散的,不完整的内存区域,如果想再存储较大的对象时,就会促使再次进行一次回收。
二、复制算法(Copying)
复制算法是为了解决标记清除算法效率不高而产生的。该算法的思路就是将内存空间一分为二,一模一样大小相等的内存空间。每次只使用其中一块来存储对象,当这一块内存使用的差不多的时候,将这块中还存活的对象复制到另一块内存中,然后将原来的已经使用过的内存完全清理掉。
这种算法的优点和不足:
优点:每次回收对一半的空间进行回收,也不需要考虑内存碎片化,不整合的问题了。提升了回收效率。
不足:对内存一分为二,始终对一半的内存操作,浪费了一半的内存
三、标记-整理算法(Mark-Compact)
标记-整理算法采用标记-清除算法一样的标记方式进行对象的标记,但在清除时不同,在回收那些不存活的对象占用的空间后,将后面活着的对象依次向前移动。将所有活着的对象都移动成内存空间中一段连续的区域,之后的连续区域都是可分配的没有使用的内存空间。因此成本很高,但是解决了碎片化内存的问题。
四、分代收集算法
分代收集算法是目前大部分JVM的垃圾收集器采用的算法。其核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为老年代和新生代,在堆区之外还有一个永久代。老年代的特点就是每次垃圾回收时只有少量的对象需要被回收,而新生代每次回收时都有大量的对象需要被回收,于是该算法就是根据这些代的特点采取合适的收集算法
接下来就逐一介绍下这些代的区别和对应的回收算法:
1.年轻代
回收算法以Copying为主,新创建的对象都存放在这里。因为大多数对象很快变得不可达,所以大多数对象在年轻代中创建,然后消失。当对象从这块内存区域消失时,我们说发生了一次“minor GC”(次要回收)
所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。
新生代内存按照8:1:1的比例分为一个eden(伊甸)区和两个survivor(幸存)(survivor0->surviverFrom,survivor1->survivoerTo)区。一个Eden区,两个 Survivor区(一般而言)。大部分对象在Eden区中生成。回收时先将eden区存活对象复制到一个survivor0区,然后清空eden区,当这个survivor0区也存放满了时,则将eden区和survivor0区存活对象复制到另一个survivor1区,然后清空eden和这个survivor0区,此时survivor0区是空的,然后将survivor0区和survivor1区交换,即保持survivor1区为空, 如此往复。
当survivor1区不足以存放 eden和survivor0的存活对象时,就将存活对象直接存放到老年代。若是老年代也满了就会触发一次Full GC(Major GC),也就是新生代、老年代都进行回收。
新生代发生的GC叫做Minor GC,MinorGC发生频率比较高(不一定等Eden区满了才触发)。
2.老年代
回收算法主要以标记-整理算法Mark-Compact为主,没有变得不可达,存活下来的年轻代对象被复制到这里。这块内存区域一般大于年轻代。因为它更大的规模,GC发生的次数比在年轻代的少。对象从老年代消失时,我们说“major GC”(或“full GC”)发生了
在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。
内存比新生代也大很多(大概比例是1:2),当老年代内存满时触发Major GC即Full GC,Full GC发生频率比较低,老年代对象存活时间比较长,存活率标记高。
3.永久代
用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate 等,在这种时候需要设置一个比较大的永久代空间来存放这些运行过程中新增的类。
注意:这块内存区域绝对不是永久的存放从老年代存活下来的对象的!!!在这块内存中有可能发生垃圾回收。发生在这里垃圾回收也被称为major GC
G1
G1(Garbage-First)回收器是在JDK1.7中正式使用的全新垃圾回收器,G1拥有独特的垃圾回收策略,从分代上看,G1依然属于分代垃圾回收器,它会区分年代和老年代,依然有eden和survivor区,但从堆的结构上看,它并不要求整个eden区、年清代或者老年代都连续。它使用了全新的分区算法。其特点如下:
并行性:G1在回收期间,可以由多个GC线程同时工作,有效利用多核计算能力。
并发性:G1拥有与应用程序交替执行的能力,因此一般来说,不会在整个回收期间完全阻塞应用程序。
分代GC:与之前回收器不同,其他回收器,它们要么工作在年轻代要么工作在老年代。G1可以同时兼顾年轻代与老年代。
空间整理:G1在回收过程中,会进行适当的对象移动,不像CMS,只是简单的标记清除,在若干次GC后CMS必须进行一次碎片整理,G1在每次回收时都会有效的复制对象,减少空间碎片。
可预见性:由于分区的原因,G1可以只选取部分区域进行内存回收,这样缩小了回收范围,因此对于全局停顿也能得到更好的控制。