垃圾收集算法
标记-清除算法
定义:标记所有需要回收的对象,在标记完成后统一回收所有被标记的对象。
缺点:标记与清楚效率低,同时产生大量不连续的内存碎片占用空间。
复制算法
定义:将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
缺点:将内存缩小为原来的一半。
标记-整理算法
标记:标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
分代收集算法
根据对象存活周期的不同将内存划分为几块,一般把java堆分为新生代和老年代,可以根据各个年代的特点采用最适用的收集算法。
新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。
老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记—清理”或者“标记—整理”算法来进行回收。
HotSpot的算法实现
枚举根节点
当执行系统停顿下来后,并不需要一个不漏地检查完所有执行上下文和全局的引用位置,虚拟机有办法直接得知哪些地方存放着对象引用。(OopMap数据结构记录偏移量)
安全点
即程序执行时并非在所有地方都能停顿下来开始GC,只有在到达安全点时才能暂停。(如方法调用、循环跳转、异常跳转)。
A:抢先式中断(Preemptive Suspension)
不需要线程的执行代码主动去配合,在GC发生时,首先把所有线程全部中断,如果发现有线程中断的地方不在安全点上,就恢复线程,让它“跑”到安全点上。
B:主动式中断(Voluntary Suspension) (主流)
当GC需要中断线程的时候,不直接对线程操作,仅仅简单地设置一个标志,各个线程执行时主动去轮询这个标志,发现中断标志为真时就自己中断挂起。轮询标志的地方和安全点是重合的,另外再加上创建对象需要分配内存的地方。
安全区域
即在一段代码片段之中,引用关系不会发生变化,在这个区域中的任意地方开始都是GC都是安全的,可以看作是扩展的安全点。
工作流程:
在线程执行到Safe Region中的代码时,首先标识自己已经进入了Safe Region,那样,当在这段时间里JVM要发起GC时,就不用管标识自己为Safe Region状态的线程了。在线程要离开Safe Region时,它要检查系统是否已经完成了根节点枚举(或者是整个GC过程),如果完成了,那线程就继续执行,否则它就必须等待直到收到可以安全离开Safe Region的信号为止。
垃圾收集器
Serial收集器
简单而高效,对于限定单个cpu的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集,可以获得最高的单线程收集效率。
-XX:+UseSerialGC
-新生代、老年代使用串行回收
-新生代复制算法
-老年代 标记压缩
####ParNew收集器(收集新生代)
采用多线程收集,与Serial收集器类似,但可以与CMS收集器(收集老年代)配合工作。
-XX:+UseParNewGC
-新生代并行
-老年代串行
serial 新生代的并行版本
-XX:ParallelGCThreads 限制线程数量
Parallel Scavenge收集器
A:并行(Parallel): 指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状
态。
B: 并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户程序在继续运行,而垃圾收集程序运行于另一个CPU上。
C:吞吐量(Throughput):。所谓吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)。
CMS等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量(Throughput)。
-XX:+UseParallelGC
使用Parallel收集器 + 老年代串行
-XX:+UseParallelOldGC
使用Parallel收集器 + 老年代并行
-XX:MaxGCPauseMills
最大停顿时间,单位毫秒
GC尽力保证回收时间不超过设定值
-XX:GCTimeRatio
0 - 100范围
垃圾收集时间占总时间的比
默认99 即最大允许1%时间做GC
CMS收集器(Concurrent Mark Sweep)(标记清除,容易产生碎片,耗cpu)
是一种以获取最短回收停顿时间为目标的收集器,可与用户线程并发执行。
- 初始标记
根可以直接关联到的对象
- 并发标记(和用户线程一起执行)
主要标记过程,标记全部对象
-重新标记
由于并发标记时,用户线程依然运行,因此正式清理前,再做纠正
-并发清理(和用户线程一起执行)
基于标记结果,直接清理对象。
实现步骤:初始标记(CMS initial mark)、并发标记(CMS concurrent mark)、重新标记(CMS remark)、 并发清除(CMS concurrent sweep)。
-XX:+UseConcMarkSweepGc 使用CMS收集器
-XX:CMSInitiatingOccupancyFraction 设置触发GC的阈值
G1收集器(Garbage-First)
A:并行与并发:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短Stop-The-World停顿的时间。
B:分代收集:能够采用不同的方式对处理新创建的对象和已存活了一段时间且经过多次GC的旧对象。
C:空间整合:运行期间不会产生内存空间碎片,收集后能提供规整的可用内存。
D:可预测的停顿:能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃拉圾收集上的时间不得超过N毫秒。
E:java内存布局:将整个堆划分为多个大小相等的独立区域(region),G1跟踪各个Region里面的垃圾堆积的价值大小,在后台维护一个优先表,每次根据允许的收集时间,优先回收价值最大的region(G1名称的由来)。
F:运行步骤(不计算Remembered Set操作):初始标记、并发标记、最终标记、筛选回收。