上一篇文章我们了解了jvm的内存分配,在这篇文章我们将讲一讲Java虚拟机的垃圾回收。
给对象中添加一个引用计数器,每当有一个地方引用他时就给计数器值加一;当引用失效时,计数器值就减一;任何时刻计数器为0的对象就是不可能再被使用的。
缺点:很难解决对象之间互相循环引用的问题。
以“GC Root”对象为起始点,从此节点向下搜索,搜索所走的路径成为引用链,当一个对象和GC Root之间没有任何引用链的时候,则此对象为不可用对象。
如上图所示,Object1到Object4与GC Root之间存在引用链,所以Object1到Object4的对象是可达对象,而Object5和Object6没有雨GC Root相关的引用链,所以Object5和Object6是不可达对象,是可以回收的对象。
Java中可以被称为GC Root的对象有以下几种:
如果一个对象在可达性分析时没后没有与GC Root相连接的引用链,它将会第一次标记并筛选,筛选条件是该对象是否有必要执行finalize()方法,如果有必要执行finalize()方法,对象只要重新与引用链上的任何一个对象建立关联即可,拿在第二次标记时将他移除“即将回收”集合。任何对象的finalize()方法只会被调用一次,如果对象面临下一次回收,它的finalize()方法不会被再次执行。
首先标记出所有要回收的对象,在标记完成后统一回收被标记的对象。
缺点: 1、效率问题,标记和清除两个过程的效率都不高。 2、空间问题,标记清除会产生大量不连续的内存碎片,空间碎片太多会导致以后程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得进行另一次垃圾收集动作。
将内存安容量分为大小相等的两块,每次只使用其中一块,当着一块内存用完后,将存活的对象复制到另一块上面,再把已使用的内存清理掉。
一般虚拟机是将内存分为一块较大的Eden空间和两块较小的Survivor空间。每次使用?Eden和其中一块Survivor,回收时,将Eden和Survivor还存后的对象复制到Survivor空间,再清理掉刚才用到的Survivor和Eden空间。当Survivor内存不足时会用到其他内存(老年代)进行分配担保。
缺点:在对象存活率较高时就要进行较多的复制操作,效率会变低,老年代一般不能直接选用这种做法。
标记过程与标记—清除算法相同,然后让所有存活的对象都像一端移动,然后直接清理掉端边界以外的内存。适用于老年代整理。
一般根据对象存活周期将对象划分为几块。Java堆分为新生代和老年代。新生代一般采用复制算法,而老年代对象存活较高,没有额外空间对它进行分配担保,就必须使用标记—清除或标记—整理算法。
是虚拟机在client模式下默认的新生代收集器,是单线程收集器,必须停掉其他所有工作线程,知道他收集结束。
是Serial收集器的多线程版本。是许多运行在server模式下的虚拟机的首选的新生代收集器。除了Serial收集器外,只有它能与CMS收集器配合工作。
并行多线程的新生代收集器。CMS等收集器的特点是尽可能缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目的是达到一个可控制吞吐量。吞吐量是指CPU用于运行用户代码的时间与CPU总消耗的时间的比值
是Serial收集器的老年代版本,单线程收集器。主要是给client模式下的虚拟机使用。在server模式下:一是可以与Parallel Scavenge收集器配合使用。另一方面是作为CMS收集器的后备方案。
是Parallel Scavenge收集器的老年代版本,使用多线程和标记—整理算法。
是一种以获取最短回收时间为目标的收集器。基于标记—清除算法实现。运作过程:
其中初始标记和重新标记需要“stop the world”,并发标记和并发清除是和用户线程一起进行的。
缺点: 1、对CPU资源敏感,因为占用了一部分线程而导致应用程序变慢,总吞吐量会降低。
2、收集器无法处理浮动垃圾。
3.采用标记—清除算法会产生大量空间碎片。
面向服务端应用的垃圾收集器。优点如下:
它将整个Java堆分为多个大小相等的独立区域,保留新生代和老年代概念,但他们不是物理隔离,都是一部分Region的集合。G1跟踪各个Region里面的垃圾堆积的价值大小,在后台维护一个优先列表,每次根据允许的手机时间,优先回收价值大的Region。
G1的操作步骤:
需要大量连续的内存空间的Java对象,最典型就是很长的字符串以及数组。
虚拟机给每一个对象定义年龄计数器,在Eden代出生并经过一次Minor GC仍存后,并能被Survivor接收,被移到Survivor空间中,年龄加一。在Survivor中每熬过一次GC,年龄就加一。当年龄到一定长度后就进入老年代。
如果在Survivor中的相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于等于改年龄的对象就会进入老年代。
在Minor GC前虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象的总空间,如果条件成立,那么Minor GC可以确保安全。否则虚拟机会查看HandelPromotionFailure设置的值是否允许担保失败,如果是,则在检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,尝试进行一次Minor GC。否则进行一次Full GC