1 GC要做的四件事
2 判断哪些是垃圾
2.1 引用计数法
在Java中,引用和对象是有关联的,如果要操作对象必须用引用进行,因此很显然一个办法就是通过引用计数来判断该对象是否可以回收
,简单讲,如果一个对象没有任何与之关联的引用,即他的引用计数都不为0,则说明对象不太可能被用到,那么这个对象就是可回收对象。
2.2 根搜索算法(可达性分析)
因为引用计数法存在引用循环的问题,Java还使用了可达性分析的方法,通过一系列的“GC roots”对象作为起点搜索,如果在“GC roots”和一个对象之间没有可达的路径,则称该对象是不可达的。注意的是不可达对象不一定是可回收对象,需要经过两次不可达标记后才能被确定为可回收对象
。
3 怎么回收垃圾(垃圾回收算法)
3.1 标记清除法(Mark-Sweep)
最简单的垃圾回收算法,分为两个阶段,标记和清除
,标记阶段标记出所有将要回收的对象,清除阶段将被标记的对象空间进行回收。
(该图片来着网络,如有侵权请联系删除)
遗留问题:内存的碎片化严重,后续可能会产生浪费。
3.2 复制算法(Coping)
为了解决标记清除法的内存碎片化问题,提出了复制算法,主要过程是将内存按容量相等的条件划分成两块,每次只使用其中的一般,当这一块内存满后将存活的对象复制到另一块上去,把已使用的清除掉。
(该图片来着网络,如有侵权请联系删除)
遗留问题:可用内存被压缩到了原来的一半,而且如果存活对象增多的话该算法的效率会降低
3.3 标记整理算法(Mark-Compact)
和Mark-Sweep算法相同,标记后不是清理对象,而是将存活对象移动到内存的另一端,然后删除端边界外的对象。
(该图片来着网络,如有侵权请联系删除)
3.4 分代收集算法(Generational Collecting)
目前大部分JVM采用的垃圾回收算法,其核心思想是根据对象存活的不同生命周期将内存划分为不同的区域,一般情况下将GC堆划分为老年代、新生代,相比之下新生代的回收次数和单次回收的数量要大于老年代。
3.4.1 新生代与复制算法
每次使用Eden空间和其中的一块Survivor空间
,当进行回收时,将该两块空间中还存活的对象复制到另一块Survivor空间中。
3.4.2 老年代与标记复制算法
因为老年代每次回收对象较少,因此采用Mark-Compact算法。
当Eden Space和From Space内存不足时会发生一次GC,结束后存活的对象将会转移到To Space,当To Space内存不够时就会移动到老年代,对象在Survivor区躲过一次GC后,其年龄会+1 ,默认下年龄到15时对象会被移动到老年代。
4 不同内存区域垃圾的回收方式
4.1 新生代
使用Minor GC进行回收,采用复制算法,年轻代分为Eden区和Survivor 区。
Eden区:对象刚被创建的时候,存放在Eden 区,如果Eden区放不下,则放在Survivor区,甚至老年代中。
Survivor区: Minor回收时使用,将Eden中存活的对象存入Survior中(From),再一次Minor时,将Survior From 中的对
象存入Survior To中,清除Survior From,下一次Minor时重复次步骤,Survior From变成Survior To,Survior To变成
Survior From,依次循环,同时每次 Minor,对象的年龄都+1,年龄增加到一定程度的对象,移动到老年代中。
4.2 老年代
存放生命周期较长的对象,使用标记-清理算法或者标记-整理算法进行回收。
5 扩展:常见的垃圾收集器