判断对象是否死亡的方法:
(1)引用计数法:若对象存在引用,那么该对象的引用计数器加1,若该对象的引用计数器为0表示没有被引用,则被回收
(2)可达性分析算法:判断该对象跟gc root之间有没有关联,若没有关联那么被回收。
可以作为gc roots的对象:
(1)虚拟机栈中的引用对象
(2)方法区中类的静态属性所引用的对象
(3)方法区中常量所引用的对象
引用:
强引用:直接关联着的对象,eg:A a = new A();
软引用:在发生内存溢出之前会将软引用的对象清除掉,若还是内存不够实用,那么抛出异常
弱引用:不论内存是否足够,都会回收的对象
虚引用:不会对内存造成影响。
垃圾收集算法:
(1)标记清除算法
缺点:容易造成大量的空间碎片,提前触发gc
(2)复制算法:
优点:不会造成空间碎片
(3)标记整理算法:
整合上述两者算法的优缺点而产生的。
(4)分代垃圾收集算法
gc roots实现原理:
可达性分析时,需要确保对象之间的引用关系的正确,否则会造成严重的后果,因此 可达性分析时就需要将所有的用户线程停止下来,来判断是否可达。
jvm借助oopmap来保存对象之间的引用关系,但是众多的oopmap会造成空间上的消耗,因此出现了安全点。
安全点中记录了所有的引用关系,因此可以在安全点上来进行可达性分析。
安全点策略:抢占式中断 主动中断。
抢占式中断 : 发生可达性分析时,停止所有的线程,若有线程停止的地方不在安全点上,那么恢复线程,在安全点上停止
主动中断 : gc在安全点上设置可达性分析的标志,用户线程轮询该标志,来停止线程。(主要使用的方式)
安全区:在安全区进行可达性分析,是安全的,解决了由于用户线程挂起而不能到达安全点的问题。
垃圾收集器:
(1)serial收集器:用于新生代,单线程,使用复制算法
(2)parnew收集器:新生代,多线程,复制算法
(3)parallel Scavenge收集器:新生代,多线程,复制算法,目标提高用户的吞吐量。
降低gc时间:通过减少新生代的大小来实现,导致频繁gc,降低吞吐量
(4)serial Old收集器:serial收集器的老年代版本,标记-整理算法,单线程
(5)parallel Old收集齐:parallel Scavenge收集器的 老年代版本,多线程,标记-整理算法
(6)cms: 多线程,并发,标记清除算法,老年代。
gc过程:初始标记(标记gc roots的关联关系) ---》 并发标记(用户线程边执行,边标记) ----》 最终标记(标记并发标记过程中gc roots发生变化的节点) ---》并发清理
缺点:占用部分cpu导致吞吐量降低。 无法清除浮动垃圾(并发标记时产生)。使用了标记-清除算法导致空间碎片
(7)G1:并行,并发,分代收集,空间整合(整体采用标记-整理算法,局部使用复制算法),可预测的停顿(后台维护一张优先列表,根据回收时间来对region区域进行回收),老年代。
gc过程跟cms相同。
如何避免全堆扫描:jvm使用remember set来记录分代对象之间的关联关系,来避免全堆扫描。