GC策略解决了哪几个问题?

分为以下几个问题:

1、哪些对象可以被回收。

2、何时回收这些对象。

3、采用什么样的方式回收。



1.哪些对象可以被回收?

对象回收时会根据根搜索算法来确定回收的对象.

   在JAVA语言中,可以当做GC roots的对象有以下几种:

     1、虚拟机栈中的引用的对象。

     2、方法区中的类静态属性引用的对象。

     3、方法区中的常量引用的对象。

     4、本地方法栈中JNI的引用的对象。

然而根搜索算法并不能满足何时及应采用何种方式回收这两个问题,所以也就衍生出了垃圾搜索的三种算法,分别是

标记-清除算法、复制算法、标记-整理算法



2.怎样回收?

三种算法

标记/清除算法:就是当程序运行期间,若可以使用的内存被耗尽的时候,GC线程就会被触发并将程序暂停,随后将依旧存活的对象标记一遍,最终再将堆中所有没被标记的对象全部清除掉,接下来便让程序恢复运行。

缺点:效率低,且清理时需要停止应用程序;清理出的空闲空间是不连续的.


复制算法:将内存划分为两个空间,将对象过滤排列后在两个空间之间来回运作.注意,必有一个空间是空闲的.

缺点:浪费了一半的内存;如果对象存活率高,将十分影响效率

适用于对象存活率不高的情况.


标记/整理算法:遍历GC Roots,然后将存活的对象标记.然后移动所有存活的对象,并将他们按照内存地址顺序排序,最后将地址末端以后的对象全部回收.

缺点:因为要遍历所有,并且要整理地址,效率甚至比复制算法还低.


比较三种算法

效率:复制算法>标记/整理算法>标记/清除算法(此处的效率只是简单的对比时间复杂度,实际情况不一定如此)。

内存整齐度:复制算法=标记/整理算法>标记/清除算法。

内存利用率:标记/整理算法=标记/清除算法>复制算法。





3.分代搜索算法

上面三种算法所适应情况不同,所以产生了分代搜索算法,其实也就是对三种算法的实际应用.

年轻代:采用复制算法,但会划为三个区域: 伊甸园(Eden   80%), 幸存区(Survivor 10%) *2.

当年轻代对象发生以下两种情况时则进入老年代:


1、在新生代里的每一个对象,都会有一个年龄,当这些对象的年龄到达一定程度时(年龄就是熬过的GC次数,每次GC如果对象存活下来,则年龄加1),则会被转到年老代,而这个转入年老代的年龄值,一般在JVM中是可以设置的。

2、在新生代存活对象占用的内存超过10%时,则多余的对象会放入年老代。这种时候,年老代就是新生代的“备用仓库”。



年老代:  因其存活率高,一般采用标记/整理或标记/清除算法.


永久带:  同年老代.



4.GC的时机


普通GC(minor GC):只针对新生代区域的GC。


全局GC(major GC or Full GC):针对年老代的GC,偶尔伴随对新生代的GC以及对永久代的GC。


由于年老代与永久代相对来说GC效果不好,而且二者的内存使用增长速度也慢,因此一般情况下,需要经过好几次普通GC,才会触发一次全局GC。