前言
前面说了Java内存分配,其中堆 就是GC的主要位置,本章也主要讲堆GC
判断Java对象是否存活
1.引用计数算法
引用计数算法 就是给对象添加一个计数器,初始值为0,有一个地方引用它时,计数器加一,当一个引用失效时,计数器建议,计数器为0 此对象不可用。但是有个缺点,就是当两个对象互相引用时,这两个对象可能都是不可获得的,但是由于引用计数器就不为零,所以依然被判为存活
2.可达性分析算法
算法思路是通过一系列GC Roots 的对象作为起始点,从这些节点向下搜索,当一个对象到GC Roots时 没有任何引用链相连,证明此对象是不可用的。如下图,从GC Root 不能到达ObjD ObjF ObjE 所以这三个对象是不可用的,可做GC Roots的对象有 虚拟机栈中引用的对象,方法区中静态属性引用的对象和常量引用的对象、本地方法栈引用的对象
JVM的四种引用
1.强引用:程序中普遍存在的一种引用 Object o = new Object();垃圾收集器永远不会回收被强引用的对象。
2.软引用:当我们存在有用但不是必须得对象时,例如缓存就可以使用软引用; 对于软引用关联着的对象,在发生GC时,将会把这些对象列入第二次的GC对象中 ;其实现类 SoftReference
3.弱引用: 弱引用用来描述非必须对象;对于其关联的对象只能存活到下一次的GC;其实现类 WeakReference
4.虚引用: 它并不影响对象的生命周期,为一个对象设置虚引用的目的就是为了这个对象被收集器回收时收到一个系统通知 ;其实现类 PhantomReference ,配合 ReferenceQueue 队列使用
垃圾回收算法
1.标记-清除
先标记出要回收的对象,然后全部清除;有两个缺点1:标记与清除的效率都不高,2:产生内存碎片 容易导致GC提前
2.复制
复制算法 将内存划分为相等的两块区域A和B,一次只用其中一个模块,当需要GC时,将A中所有存活的对象复制到B,然后清除A使用B,循环这样操作。这样效率会很高 但是会导致内存大小只有一半
3.标记-整理
先标记出要回收的对象,然后让所有活动对象 向另一端移动 ,最后直接清理端边界以外的内存,其解决了 产生内存碎片的问题
4.分代收集管理
根据对象的存活周期的不同 ,java堆分为新生代和老年代,这样可以根据各个年代的特点采用适当的收集算法。在新生代,每次垃圾回收都会有大批的对象死去,只有少量存活,就采用复制算法,而且由于每次GC都会回收掉大量对象,在新生代还分为Eden 和两个Survivor 其比例为8:1:1 复制算法每次都将 Eden + Survivor1 的存活对象复制到 Survivor2 里面 周而复始,保证其中Survivor 是空的。而老年代中因为对象存活率高,没有额外空间堆他进行分配担保,则采用了 标记-整理 算法进行回收。
垃圾回收器
HotSpot虚拟机所包含的7种收集器
新生代收集器:Serial、ParNew、Parallel Scavenge
老年代收集器:CMS、Serial Old、Parallel Oldpost
整堆收集器: G1
几个相关概念:
并行收集:指多条垃圾收集线程并行工做,但此时用户线程仍处于等待状态。学习
并发收集:指用户线程与垃圾收集线程同时工做(不必定是并行的可能会交替执行)。用户程序在继续运行,而垃圾收集程序运行在另外一个CPU上。
吞吐量:即CPU用于运行用户代码的时间与CPU总消耗时间的比值(吞吐量 = 运行用户代码时间 / ( 运行用户代码时间 + 垃圾收集时间 ))。例如:虚拟机共运行100分钟,垃圾收集器花掉1分钟,那么吞吐量就是99%
关于7个垃圾收集器的详细介绍请参照 https://www.shangmayuan.com/a/447f21a762c7425597de3c58.html
总结
Minor GC 与 Full GC 区别
新生代GC (MinorGc): 发生在新生代的垃圾收集动作。Minor GC 非常频繁,回收速度较快
老年代GC (Major GC/ Full GC): 发生在老年代的GC,且速度非常慢
内存分配规则
大多数情况,对象在新生代Eden 区中分配,当Eden区没有足够空间进行分配时,虚拟机将发起MinorGC
Minor GC 和 Full GC 有什么区别?
新生代 GC (Minor GC) :发生在新生代的垃圾收集动作。Minor GC 非常频繁,回收速度比较快。
老年代 GC (Major GC/Full GC):发生在老年代的 GC, Major GC 一般比 Minor GC 慢 10 倍以上。
大对象直接进入老年代
长期存活的对象进入老年代: 虚拟机给每个对象定义了一个年龄计数器,如果对象在Eden 出生在Survivor 区中每经历一次Minor GC ,则年龄增加1岁,当年龄到一定程度 (默认15岁),就会进入老年代(这里不是必定的)。
动态对象的判定:在Survivor 空间中相同年龄所有对象大小的总和大于Survivor 空间的一半,年龄大于等于该年龄的对象 就可以直接进入老年代
空间分配担保
在发生Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立那么Minor GC 是可以确保安全的,如果不成立,虚拟机则会查看 HandlePromotionFailure 的设置值 是否允许担保失败,如果允许 那么会继续检查老年代最大可能连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试进行一次Minor GC;如果小于 或者 HandlePromotionFailure 设置不允许毛线,那么将先进行一次Full GC。
Stop The World
Stop- the- World 简称STW,指的是GC事件发生过程中,为了保证正确的,Java应用的除了垃圾收集器线程之外的所有线程都会被挂机,它会导致系统全局的停顿。
END