JVM垃圾回收
1.GC类型
- 新生代垃圾回收
新生代的垃圾回收(以下称为Minor GC),大多数情况下,对象在新生代中 eden 区分配。当 eden 区没有足够空间进行分配时,虚拟机将发起一次 Minor GC.下面我们来进行实际测试以下。 - 老年代垃圾回收
老年代的垃圾回收(以下称为Major GC),指发生在老年代的 GC,出现了 Major GC 经常会伴随至少一次的 Minor GC(并非绝对),Major GC 的速度一般会比 Minor GC 的慢 10 倍以上。 - 整体垃圾回收
整体的垃圾回收(以下称为Full GC),区别于Major GC和Minor GC,清理整个堆空间—包括年轻代和老年代。
2.垃圾收集器
-
常用于新生代垃圾收集器
- Serial
Serial单线程收集器,在进行垃圾回收时只会用一条垃圾收集线程去完成垃圾收集工作,更重要的是它在进行垃圾收集工作的时候必须暂停其他所有的工作线程( “Stop The World” ),直到它收集结束。
使用在新生代时采用复制算法,老年代使用标记整理法。- ParNew
Serial收集器的多线程版本,除了在垃圾回收时采用多条线程以外没有区别。新生代采用复制算法,老年代采用标记-整理算法。
除了 Serial 收集器外,只有它能与 CMS 收集器配合工作。- Paraller Scavenge
Parallel Scavenge 收集器也是使用复制算法的多线程收集器,区别在于Parallel Scavenge 收集器关注点是吞吐量(高效率的利用 CPU)。CMS 等垃圾收集器的关注点更多的是用户线程的停顿时间(提高用户体验)。所谓吞吐量就是 CPU 中用于运行用户代码的时间与 CPU 总消耗时间的比值。新生代采用复制算法,老年代采用标记-整理算法。
- Serial
-
常用于老年代的垃圾收集器
- Paraller Old
Parallel Scavenge 收集器的老年代版本。使用多线程和“标记-整理”算法。在注重吞吐量以及 CPU 资源的场合,都可以优先考虑 Parallel Scavenge 收集器和 Parallel Old 收集器。 - Serial Old
Serial 收集器的老年代版本,它同样是一个单线程收集器。它主要有两大用途:一种用途是在 JDK1.5 以及以前的版本中与 Parallel Scavenge 收集器搭配使用,另一种用途是作为 CMS 收集器的后备方案。 - CMS
- Paraller Old
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。它非常符合在注重用户体验的应用上使用。是 HotSpot 虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。CMS中的“MS”即Mark Sweep翻译为标记清除,代表CMS区别于其他老年代收集器,是基于标记清除算法实现的
它的运作过程分为四步:
- 初始标记:STW,标记存活的GC Roots
- 并发标记:Root Tracing的过程,根据存活的Root标记其他存活对象
- 重新标记:STW,因为是并发标记所以在标记过程中可能出现被标记对象的改动,重新标记检查并修改这些改动
- 并发清除:清除未标记的对象
3.垃圾回收机制
-
复制算法
把堆等分成两块区域, A 和 B,区域 A 负责分配对象,区域 B 不分配, 对区域 A 使用以上所说的标记法把存活的对象标记出来,然后把区域 A 中存活的对象都复制到区域 B(存活对象都依次紧邻排列)最后把 A 区对象全部清理掉释放出空间,这样就解决了内存碎片的问题了。 -
标记清除法
先根据可达性算法标记出相应的可回收对象(图中黄色部分)
对可回收的对象进行回收 -
标记整理法
前面两步和标记清除法一样,不同的是它在标记清除法的基础上添加了一个整理的过程 ,即将所有的存活对象都往一端移动,紧邻排列(如图示),再清理掉另一端的所有区域,这样的话就解决了内存碎片的问题。
4.什么时候垃圾回收
-
分析算法
- 可达性分析法
确定多个GC Roots,清除不被Roots关联的对象
哪些对象可以作为GC Roots:
1. 虚拟机栈(栈帧中的局部变量表)中引用的对象
2. 方法区中类的静态属性引用的对象
3. 方法区中常量引用的对象
4. 本地方法栈中native方法引用的对象 - 引用计数器法
缺点:循环引用时无法清除对象
- 可达性分析法
-
触发机制
- 手动调用System.gc()
- 老年代空间不足
- 新生代空间不足
- 通过minor gc后进入老年代的平均年龄大于老年代可用内存
- 新生代gc后对象大小大于survivor区空间大小