JVM之GC机制

1.判断垃圾是否可以回收
1)引用计数算法
为对象添加一个计数器,有一个地方被引用了计数器就加1,失效就减1,等于0则代表对象不在被使用
java不采用引用计数这种算法,但是无法解决对象互相引用的问题。

2)可达性分析算法
基本思路:以一个"GC Roots"为起点,从GC Roots向下搜索,搜索所走过的路为引用链,如果一个对象到GC Roots没有任何引用链,则该对象就是不可用的
在java中有四种对象类型可以是GC Roots
a.虚拟机栈中的引用对象
b.本地方法栈中JNI引用的对象
c.方法区中类静态属性所引用的对象
d.方法区中常量引用的对象

2.垃圾回收算法
1)标记清除
标记—清除算法是最基础的收集算法,它分为"标记"和"清除"两个阶段:首先标记出所需回收的对象,在标记完成后统一回收掉所有被标记的对象,它的标记过程其实就是前面的根搜索算法中判定垃圾对象的标记过程。
标记清除算法的执行情况如下:
垃圾回收前


回收前

垃圾回收后


回收后

标记清除的缺点:一是内存空间碎片化,创建大对象很容易因为找不到连续的内存空间引起又一次GC,二是标记和清除两个阶段的效率都很低
2)复制
复制算法是针对标记—清除算法的缺点,在其基础上进行改进而得到的,它将内存按容量分为大小相等的两块,每次只使用其中的一块,当这一块的内存用完了,就将还存活着的对象复制到另外一块内存上面,然后再把已使用过的内存空间一次清理掉。
复制算法的执行情况如下
垃圾回收前
回收前

垃圾回收后


回收后

复制算法的优点:
不用考虑内存碎片化的问题
复制算法的缺点:
将一次可以分配的内存空间缩小了一遍,如果创建大对象,也很有可能引起GC
商用版的复制算法:将内存划分为较大的eden空间和两块较小的survivor空间,每次使用eden和其中一块survivor。回收时将存活的对象一次性复制到另外一块survivor上,最后一次性清理eden和survivor已死亡的对象。商用的复制算法只是划分比例不一样,一般为eden:survivor=8:1
空间担保机制:当存活对象大于内存空间的10%时(即存活的对象内存大小大于剩余的survivor内存大小),需要老年代进行分配担保(即直接将这些对象分配到老年代)
复制算法适合用于新生代,新生代有大量的对象死亡,复制存活对象的效率较高
3)标记整理
标记整理算法与标记清除算法中的标记过程一样,但对标记后可回收对象的处理情况有所不同,它不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。标记整理算法的回收情况如下:
回收前:

回收前

回收后:


回收后

4)分代收集
当前商业虚拟机的垃圾收集都采用分代收集,它根据对象的存活周期的不同将内存划分为几块,一般是把Java堆分为新生代和老年代。在新生代中,每次垃圾收集时都会发现有大量对象死去,只有少量存活,因此可选用复制算法来完成收集,而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用标记—清除算法或标记—整理算法来进行回收
即新生代采用复制算法,老生代采用标记整理算法或者标记清除

3.内存分配与回收策略
1)对象优先分配在新生代的eden区
2)大对象,长期存活的对象分配在老生代。大对象比如很长的字符串或者数组
大对象:可以通过-XX:PretenureSizeThreshold指定大对象的大小,超过这个设置的对象直接进入老生代。(注:这个参数只对Serial和ParNew两款收集器有用)
怎样算长期存活对象:虚拟机给每个对象定义了一个对象年龄(Age)计数器,如果对象在Eden出生并且经过第一次Minor GC后仍存活,并且能被survivor容纳,将被移动到survivor空间中,对象年龄设为1,对象在survivor每熬过minor gc,年龄就加1岁,当它年龄增加到15(默认为15),这个对象就会存放到老年代。晋升老年代的年龄阈值默认为15,可以通过参数-XX:MaxTenuringThreshold设置。虚拟机对其的优化:是对象的年龄达到阈值才将对象存放入老生代。如果在survivor空间中相同年龄所有对象大小的总和大于survivor空间的一半,年龄大于等于或等于该年龄的对象就会进入老年代

新生代对象的特点:对象存活率较低
老年代对象的特点:对象存活率较高

4.Minor GC和Full GC的区别
1)Minor GC发生在新生代。特点:发生频繁,回收速度较快
为对象分配内存时,如果Eden区没有足够的空间进行分配将会引起一次Minor GC
2)Full GC发生在老生代。特点:往往伴随至少一次Minor GC(Parallel Scavenge收集器特例),回收速度非常慢

5.空间分配担保
前面提到复制算法时曾经讲到:如果存活对象大小大于剩余survivor空间大小,就需要通过老生代的空间分配担保机制将对象存放到老生代。
空间分配担保机制的过程:
在发生一次minor gc之前,虚拟机会先去检查老生代的最大可用的连续空间是否大于新生代所有对象总空间,如果成立,则这次minor gc是安全的。如果不成立,虚拟机会查看HandlePromotionFailure设置值是否允许担保失败,如果允许,检查老生代的最大可用的连续空间是否大于历代晋升到老年代对象的平均值,如果大于,会进行一次可能失败的minor gc。如果小于,或者HandlePromotionFailure不允许担保失败,则进行一次full gc.jdk6以后这个参数将失效,只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行一次minor gc,否则将会进行一次full gc

6.垃圾收集器
垃圾收集器根据收集对象的类型可以分为
新生代收集器:
Serial ParNew Parallel Scavenge
老生代收集器:
CMS Serial Old Parallel Old
新生代老年代收集器:
G1
一般是新生代和老年代的垃圾收集器搭配使用,G1可以不用搭配完成新生代和老生代的GC
在细一点可以分为单线程收集器、多线程收集器和并发收集器
单线程收集器和多线程收集器的区别
单线程收集器:
只会使用一个CPU或一条收集线程去完成垃圾收集工作,并且在进行垃圾收集时,必须暂停其他所有的工作线程,直到收集结束
多线程收集器:多线程去完成垃圾收集工作,仍会暂停其他所用的工作线程
并发收集器:同时进行垃圾收集,但又不影响其他工作

参考:《深入理解jvm虚拟机》
图片来自:http://blog.csdn.net/ns_code/article/details/18076173

你可能感兴趣的:(JVM之GC机制)