JVM中的四种垃圾回收算法
垃圾回收算法只有四种:
1、标记清除算法
2、标记整理算法
3、复制算法
4、分代回收算法
注意:这四种都是基于可达性分析算法来判断是否为垃圾的。
第一、标记清除算法
步骤
:
1、先找到GC roots根来遍历将非垃圾对象进行标记。
2、他会将垃圾进行清除,就是图中的情况。
注意
:jvm并不是真正的把垃圾对象进行了遍历,把内部的数据都删除了,不是这样的,而是把垃圾对象的首地址和尾地址进行了保存,等到再次分配内存时,直接去地址列表中分配,所以清除的效率高。
优点
:清除速度快,效率高。
缺点
:会产生大量的内存碎片(就是很多不连续的内存空间),如果放入一个大的数组的时候,没有连续的内存放置大的数组,就会出现内存溢出,但是所有的内存碎片加起来可以放置一个大的对象,所有说内存使用率低,造成内存不连续。
第二、标记整理算法
步骤
:
1、先找到GC roots根来遍历将非垃圾对象进行标记。
2、它会将垃圾进行清除,并且会将非垃圾对象进行向前移动,使得内存紧凑。
优点
:不会出现内存碎片,提高了内存的利用率
缺点
:清除速度慢,因为在整理期间会有对象的拷贝和移动,并且引用内存的对象的地址要进行改变。
第三、复制算法
注意:左边是from区,右边是to区
步骤
:
1、先找到GC roots根来遍历将非垃圾对象进行标记。
2、然后将from区的非垃圾对象进行复制,到to区,并且进行整理,整理完成之后会将from区的数据进行清空,然后交换from和to区,使得from区一直是存储数据,to区一直空白的。
优点
:也不会出现内存碎片
缺点
:有效内存只有一半,只有一半存储数据,太浪费空间
第四、分代回收算法
对象头有个参数为分代年龄
。
分代回收
:
分为新生代和老年代,
新生代分为伊甸园区和幸存区,幸存区分为from和to区
。一般情况下,新生代占1/3,老年代占2/3。然后伊甸园区占8/10,幸存区占2/10,from和to区各占1/2。
先来说说minor GC 和full GC
Minor GC
又称为新⽣生代GC : 指的是发生在新生代的垃圾收集。因为Java对象大多都具备朝生夕灭的特性,因此Minor GC(采⽤用复制算法)非常频繁,一般回收速度也比较快。
Full GC
又称为 老年代GC或者Major GC : 指发生在老年代的垃圾收集。出现了了Major GC, 经常会伴随至少一次的Minor GC(并非绝对,在Parallel Scavenge收集器器中就有直接进行Full GC的策略选择过程)。Major GC的速度一般会比Minor GC慢10倍以上。
先来说一下对象存储以及垃圾回收过程
:
放入对象时,对象先会来到伊甸园区,如果伊甸园的剩余内存大小可以放下,就直接放到伊甸园区,如果伊甸园内存不够,就会进行minor GC 将伊甸园区的对象进行回收,并且将存活的对象放置from区,将分代年龄进行加1。
新生代用的是复制算法
。
minor GC 回收时,会将伊甸园区的垃圾和幸存区的垃圾都会进行回收
。
如果对象来到伊甸园区,对象放不下,又到幸存区也放不下,就会进入老年代,然后放入老年代,一直这样,直到老年代放不下的时候**,先会进行一次minor gc ,如果进行完之后,还是内存不够,就会进行full GC** ,full GC 会将新生代和老年代都会进行回收,并且会使其他的进程全部停止,称为stop the word(STW),就是平常的卡顿,如果进行full GC 之后,内存还是不够的时候,就会抛出异常OOM。
老年代的算法是标记清除或者标记整理算法
。
注意
:minor GC 也会有STW现象,只是时间短暂,老年代进行STW的时候,时间较长,因为老年代占用的内存大,而且进行的标记清除或者标记整理,时间慢,所以一般情况尽可能的少进行full GC。
还有一个问题
,
什么时候对象进入老年代
?
1、对象的分代年龄到了15岁(默认情况下,可以自己设置)。
2、大对象直接进入老年代,就是大对象在新生代放不下,进行minor GC之后还是不够的情况下,会直接放入老年代。