垃圾回收机制

垃圾回收机制

Scroll Down

对于垃圾回收这方面的知识看了一些,但总是感觉有点混乱,今天进行总结一下:

垃圾回收相关

怎么标记垃圾

1 引用计数法

引用计数算法(Reachability Counting)是通过在对象头中分配一个空间来保存该对象被引用的次数(Reference Count)。如果该对象被其它对象引用,则它的引用计数加1,如果删除对该对象的引用,那么它的引用计数就减1,当该对象的引用计数为0时,那么该对象就会被回收。

**缺点:**相互引用,导致永远不会被回收

2 可达性分析法

通过一些被称为引用链(GC Roots)的对象作为起点,从这些节点开始向下搜索,如果没有与GCROOT相链接,则表示可以被回收

GCROOTS有这些:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中 JNI(即一般说的 Native 方法)引用的对象

怎么回收垃圾

1 标记整理算法

img

2 复制算法

img

3 标记清除算法

img

堆中是怎么回收垃圾的

① minorGC

Eden 区: Eden 区没有足够空间进行分配时,虚拟机会发起一次 Minor GC,Minor GC 相比 Major GC 更频繁,回收速度也更快

survivor区:每次执行 Minor GC,会将 Eden 区和 From 存活的对象放到 Survivor 的 To 区(如果 To 区不够,则直接进入 Old 区)

分为两个区的意义:①减少被送到老年代的对象②通过复制算法解决内存碎片化

**②Major GC **

Old区:老年代占据着2/3的堆内存空间,只有在 Major GC 的时候才会进行清理,每次 GC 都会触发“Stop-The-World”。

采用标记整理算法

哪些对象会进入老年代:

1、大对象

2、在survior中长期存活对象

虚拟机给每个对象定义了一个对象年龄(Age)计数器。

3、动态对象年龄

Survivor 空间中相同年龄所有对象大小的综合大于 Survivor 空间的一半

垃圾回收器

Serial 收集器

新生代采用复制算法,老年代采用标记-整理算法。

它在进行垃圾收集工作的时候必须暂停其他所有的工作线程( "Stop The World" ),直到它收集结束

ParNew 收集器

ParNew 收集器其实就是 Serial 收集器的多线程版本,除了使用多线程进行垃圾收集外,其余行为(控制参数、收集算法、回收策略等等)和 Serial 收集器完全一样。

Parallel Scavenge 收集器

几乎和ParNew都一样,Parallel Scavenge 收集器提供了很多参数供用户找到最合适的停顿时间或最大吞吐量。

CMS 收集器

CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用,是基于**标记-清除算法**的,它的运作过程分为4个步骤:

  • 初始标记(CMS initial mark)**仅仅只是标记一下GC Roots能直接关联到的对象 ** STW
  • 并发标记(CMS concurrent mark)并发标记阶段就是进行GC Roots Tracing的过程
  • 重新标记(CMS remark)修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录 STW
  • 并发清除(CMS concurrent sweep)开启用户线程,同时 GC 线程开始对为标记的区域做清扫。

CMS收集器优点:并发收集、低停顿。

CMS收集器缺点

  • CMS收集器对CPU资源非常敏感。
  • CMS收集器是基于标记-清除算法,该算法的缺点都有(内存碎片)。
  • 停顿时间是不可预期的。

G1 收集器

G1收集器收集范围是老年代和新生代。不需要结合其他收集器使用

  • 并行与并发:G1 能充分利用 CPU、多核环境下的硬件优势,使用多个 CPU(CPU 或者 CPU 核心)来缩短 Stop-The-World 停顿时间。部分其他收集器原本需要停顿 Java 线程执行的 GC 动作,G1 收集器仍然可以通过并发的方式让 java 程序继续执行。
  • 分代收集:虽然 G1 可以不需要其他收集器配合就能独立管理整个 GC 堆,但是还是保留了分代的概念。
  • 空间整合:与 CMS 的“标记--清理”算法不同,G1 从整体来看是基于“标记整理”算法实现的收集器;从局部上来看是基于“复制”算法实现的。
  • 可预测的停顿:这是 G1 相对于 CMS 的另一个大优势,降低停顿时间是 G1 和 CMS 共同的关注点,但 G1 除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为 M 毫秒的时间片段内。

G1打破了以往将收集范围固定在新生代或老年代的模式,G1收集器将整个Java堆划分为多个大小相等的独立区域(Region)

G1堆的Region布局.png

一些gc的名词

之前老觉得混乱,这次查清楚点

Partial GC:并不收集整个GC堆的模式

  • Young GC:只收集young gen的GC
  • Old GC:只收集old gen的GC。只有CMS的concurrent collection是这个模式
  • Mixed GC:收集整个young gen以及部分old gen的GC。只有G1有这个模式

Full GC:收集整个堆,包括young gen、old gen、perm gen(如果存在的话)等所有部分的模式。

Major GC通常是跟full GC是等价的,收集整个GC堆。当有人说“major GC”的时候一定要问清楚他想要指的是上面的full GC还是old GC。

什么时候触发垃圾回收

YoungGC的触发时常在发生,当新生代的Eden区满了之后就会触发YoungGC。

FullGC在多个情况下都会被触发:

1、发生Young GC之前进行检查,如果“老年代可用的连续内存空间” < “新生代历次Young GC后升入老年代的对象总和的平均大小”,说明本次Young GC后可能升入老年代的对象大小,可能超过了老年代当前可用内存空间,此时会触发FullGC

2、当老年代没有足够空间存放对象时,会触发一次FullGC

3、如果元空间区域的内存达到了所设定的阈值-XX:MetaspaceSize=,也会触发FullGC。

4、system.gc() 强制通知系统进行垃圾回收:只是提醒或告诉虚拟机,希望进行一次垃圾回收。至于什么时候进行回收还是取决于虚拟机,而且也不能保证一定进行回收