3.1判断对象是否已死引用-计数算法
给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时候计数器为0的对象就是不可能再被使用的。
3.2判断对象是否已死引用-可达性分析算法
在主流的程序语言中,都是通过可达性分析来判断对象是否存活的。这个算法的基本思路就是通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象至GC Roots没有任何引用链相连时,则证明此对象不可用。
在java语言中,可作为GC Roots的对象包括下面几种:
虚拟机栈中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中JNI引用的对象
3.3标记-清除算法
最基础的收集算法是“标记清除”算法,如同它的名字一样,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。
3.4复制算法
为解决效率问题,一种称为“复制”的收集算法出现了,它将可用内存按容量划分为大小相等的现块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
3.5标记-整理算法
根据老年代的特点,有人提出了另一种“标记-整理”算法,标记过程仍然与“标记-清除”算法一样,但后继步骤不是直接对可回收对象进行清理,而是让所有存活对象都向一端移动,然后直接清理掉端边界以外的内存。
4、垃圾收集器
4.1Serial收集器
新生代收集器,这个收集器是一个单线程的收集器,它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。
4.2ParNew收集器
ParNew收集器其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾之外,其余行为都相同。
ParNew收集器也是使用-XX:+UseConcMarkSweepGC选项后的默认新生代收集器,也可以使用-XX:+UseParNewGC选项来强制指定它。在cpu非常多的情况下,可以使用-XX:ParallelGCThreads参数来限制垃圾收集的线程数。
4.3Parallel Scavenage收集器
Parallel Scavenage收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集器。
Parallel Scavenage收集器的目标是达到一个可控制的吞吐量。吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)
Parallel Scavenage收集器提供了两个参数用于精确控制吞吐量,分别控制最大垃圾收集停顿时间的-XX:MaxGCPauseMillis参数以及直接设置吞吐量大小的-XX:GCTimeRatio参数。
Parallel Scavenage收集器还有一个参数-XX:UseAdaptiveSizePolicy,当这个参数打开之后,就不需要手工指定新生代的大小、Eden与Survivor的比例等参数了。
4.4Serial Old收集器
Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用“标记-整理”算法。
4.5ParallelOld收集器
Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。
4.6CMS收集器
CMS收集器是一种以获取最短回收停顿时间为目标的收集器。
CMS收集器是基于“标记-清除”算法实现的,它的动作过程相对于前面几种收集器来说更复杂一些,整个过程分为4个步骤:
1、初始标记,2、并发标记,3、重新标记,4、并发清除
其中初始标记、重新标记这两个步骤仍然需要“Stop TheWorld”。
CMS收集器有3个缺点:
1、对Cpu资源非常敏感,2、无法处理浮动垃圾,3、会有大量空间碎片产生。
4.7G1收集器
G1具备如下特点:1、并行与并发,2、分代收集,3、空间整合,4、可预测的停顿。
使用G1收集器时,Java堆的内存布局就与其他收集器有很大的差别,它将整个Java堆划分为多个大小相等的独立区域,虽然还保留有新生代和老年代的概念,但新和代和老年代不再是物理隔离的了,它们都是一个部分Region的集合。
G1收集器的动作大致分为以下几个步骤:
1、初始标记,2、并发标记,3、最终标记,4、筛选回收