垃圾收集器总结

垃圾收集器
1.判断对象已死
    1.JVM不用引用计数算法,原因:无法解决对象间相互循环引用的问题
    2.根搜索算法:
    通过一系列名为“GC Roots”的对象做起点向下搜索,走过的路劲称为引用链
    当一个对象到GC Roots没有引用链,则判定对象不可用


    GC Roots:
1.虚拟机栈(栈帧中本地变量表)引用的对象
2.方法表中类静态属性引用的对象
3.方法区中常量引用的对象
4.本地方法栈中Native方法应用的对象


     根搜索不可达对象要经历两次标记过程:
     1.根搜索GC Roots不可达:第一次标记病筛选(是否有必要执行finalize方法,没覆盖或已被虚拟机执行过都没必要执行)
有必要执行的 放入f-Queue队列中,会有线程执行。
     2.GC 对F-Queue中对象二次标记,若在finalize中与引用链上对象关联,则移除待回收集合。




2.强引用:Obj a = new Obj() 只要强引用还在,对象就不会被垃圾收集器回收
  软引用:系统将发生内存溢出前 把这些对象列进回收范围中进行二次回收,若还没有足够空间 才抛异常 SoftReference
  弱引用:只生存到下一次垃圾收集发生之前 WeakReference
  虚引用:无法通过其获取对象实例,只为在垃圾回收时收到系统通知 PhantomReference




3.回收方法区:类型卸载
条件:1.该类所有示例已被回收
     2.加载该类的ClassLoader被回收
     3.Class对象未被引用,无法通过反射访问该类方法


     是否进行类回收:有参数设置:-Xnoclassgc




垃圾收集算法:

1.标记-清除算法:首先标记处所有需要回收的对象,然后统一回收掉
缺点:效率不高,空间问题,融通更易产生大量不连续的内存碎片


2.复制算法:将内存按容量划分为大小相等的两块,每次使用一块,满了就把存活的对象复制到另一块上,把已使用的内存空间一次性清理掉
虚拟机都采用这种算法回收新生代:分为一块大的Eden区,两块小的Survivor区,每次使用Eden和一块Survivor。
如另一块Survivor空间不够存放上一次新生代收集存货的对象,则放入老年区


3.标记-整理算法:标记所有需要回收的对象,让所有活着的对象向一端移动,然后直接清理掉端边界意外的内存


4.分代收集算法:根据对象存活周期不同将内存分为几块:一般十分新生代和老年代
新生代:对象朝生夕死,只有少存活,选用复制算法
老年代:对象存活率高,没有额外空间担保,使用标记-清理或标记-整理




垃圾收集器:

1.Serial收集器:Client模式下新生代 单线程收集器(简单高效,和其他单线程收集器比),收集时必须暂停所有工作线程


2.ParNew收集器:Server模式下新生代 是Serial收集器的多线程版本 -XX:ParallelGCThreads 限制垃圾手机的线程数
JDK1.5中使用CMS收集老年代时,新生代只能选择Serial或ParNew


3.Parallel Scavenge收集器: 新生代收集器 也是用复制算法,多线程收集器,与ParNew的区别是为了达到一个可控的吞吐量:(运行用户代码的 时间/用户代码时间+垃圾收集时间)
吞吐量越高,停顿时间越短,适合后台运算而不需要的太多交互的任务 也被称为“吞吐量优先的收集器”
-XX:MaxGCPauseMillis设置最大垃圾收集停顿的时间
-XX:GCTimeRatio:设置吞吐量大小  
-XX:+UseAdaptiveSizePolicy:打开后不需要手动指定新生代大小,比例。(GC自适应调节)


4.Serial Old收集器:Client模式虚拟机 Serial收集器的老年代版本,单线程 使用标记-整理算法


5.Parallel Old收集器:Parallel Scavenge的老年代版本 多线程 使用标记-整理算法
在注重吞吐量和CPU敏感的场合 优先考虑Parallel Scavenge加Parallel Old 收集器


6.CMS收集器:目标:获取最短回收停顿时间。使用标记-清除算法 
4个步骤:初始标记:标记一下GC Root能直接关联到的对象
并发标记:GC Roots Tracking
重新标记:修正并发标记期间,用户程序继续运行导致标记产生变动的那一部分
并发清除
其中初始标记和并发标记仍然需要"Stop The World"


优点:并发收集,低停顿
缺点:1.CMS收集器对CPU敏感,并发阶段,响应变慢。变种:并发标记和清理时。GC线程,用户线程交替执行,减少GC独占资源的时间
     2.无法处理浮动垃圾:
并发清理阶段用户线程继续运行,继续产生新的垃圾 CMS无法在本次收集中处理,所以要预留空间,默认在老年代使用68%被激活   -XX:CMSInitiatingOccupancyFraction设置比例 ,、

CMS运行期间预留内存不够,出现Concurrent Mode Failure 启动预案:Serial Old
     3.标记-清除算法容易产生大量空间碎片,会导致老年代还有空间,却因无法找到足够大的连续空间而Full GC
-XX:+UseCMSCompactATFullCollection:Full GC后整理碎片:停顿时间变长
-XX:CMSFullGCsBeforeCompaction:多少次不压缩Full GC后带一次压缩的


7.G1收集器:1.标记-整理算法
   2.精准控制停顿
将JAVA堆(新生代,老年代)划分多个大小固定的独立区域,维护一个优先列表,根据允许收集的时间,优先回收垃圾最多的区域




内存分配回收策略



1.对象优先分配在新生代Eden区:Eden区不够,触发Minor GC   -XX:+PrintGCDetails 收集器日志参数

2.大对象直接进入老年区:需要大量连续内存空间的对象 -XX:PretenureSizeThreshold(只对Serial 和ParNew有效)设置大于该值的对象直接放在老年区 避免Eden和两个Survivor之间发生大量内存拷贝

3.长期存活的对象进入老年代:
对象年龄计数器:若在Eden出生,经历一次Minor GC仍存活,并且Survivor能容纳,年龄就加1 默认到15 晋升到老年代

-XX:MaxTenuruingThreshold

4.动态对象年龄判定:若在Survivor中相同年龄的所有对象大小总和大于Survivor一半 直接进入老年区

5.空间分配担保:Minor GC时,虚拟机检测之前每次晋升到老年代的平均大小是否大于老年代剩余大小,若大于,Full GC. 若小于 查看HandlePromotionFailure参数是否允许担保失败,若是:只进行Minor GC 若否:Full GC  为了避免频繁Full GC 打开该参数

猜你喜欢

转载自blog.csdn.net/zhuyong7/article/details/80404348
今日推荐