Java白话基础系列—垃圾回收与GC算法
本系列呢,主要将我理解的Java基础内容,以比较白话的方式,解释出来,希望能帮助大家快速的理解一些概念。
本小结内容: 垃圾回收算法有哪些? GC算法有哪些? 有哪些 GC垃圾回收器?
文章目录
参考文档非常高,推荐!!
一、垃圾回收算法
如何找出需要回收的对象?
1.1 引用计数法(Reference Counting)
每个对象添加一个引用计数器,每个对象引用一次,计数器加1, 失去引用减1;
缺陷: 互相引用情形;
故, Sun JVM并没有采用引用计数法来进行垃圾回收。
1.2 根搜索算法
从GC Roots 开始向下搜索,如果不能打到的对象,就是可以进行回收的对象。
总结: 什么类需要回收呢? 答: 没用的类;
-
类的所有实例对象都已经被回收;
-
加载该类的ClassLoader已经被回收;
-
该类对应的反射类java.lang.Class对象没有被任何地方引用。
二、GC算法
2.1 标记-清除法(Mark-Sweep)
基础GC算法, 分为标记,清楚两个过程;
在标记阶段首先通过根节点,标记所有从根节点开始的较大对象。因此,未被标记的对象就是未被引用的垃圾对象。
然后,在清除阶段,清除所有未被标记的对象。
效率不高,且清理完成后会产生内存碎片;
2.2 复制算法(Copy)
适用于新生代,将不需要回收的对象放在控先的 survivor区, 将Eden 和 From 进行完全清理;
之后,将From 与To 转换角色,完成垃圾回收。
如果 To 不够用了, 暂时使用持久代(方法区)
新生代穿行垃圾回收器中使用了复制算法的思想
2.3 标记-整理(或叫 压缩)算法(Mark-Compact)
复制算法的高效性时间里在存活对象少,垃圾对象多的前提下的。 这种情况在年轻代经常发生,但是老年代更常见的情况是都是存活对象。如果存活的对象较多,复制的成本也将很高。
在Mark-Sweep算法上做了一些优化。 将所有可达对象做一次标记,但之后,并不是简单的清理未标记的对象,而是将所有存活对象压缩到内存的一段,清理边界外的所有空间。。 这种避免了碎片产生,有不需要两快相同的内存空间。
三、垃圾回收器
三种垃圾回收器: 串行GC(Serial GC)、并行回收(Parallel Scavenge) 和并行GC(ParNew);
3.1 Serial GC:
最基本、最古老的收集器, 依然被广泛使用, 是一种单线程垃圾回收机制。
缺陷: 正在执行的线程暂停(Stop The World );
场景: 适用于单 CPU、新生代空间较小、对暂停时间要求不高。是 Client级别默认的 GC方式,可以通过 -XX:+UseSerialGC强制指定。
3.2 ParNew GC
和Serial GC一样, 本质差别加入多线程机制,提高了效率。
3.2 Parallel Scavenge GC
扫描和复制过程采用多线程方式来进行,适用于多CPU、对暂停时间要求较短的应用上, 是server级别默认采用的GC方式。
3.4 CMS(current Mark Sweep)
CMS收集器是基于“标记-清除”算法实现,整个过程大致分为 4个步骤:
-
初始标记
-
并发标记
-
重新标记
-
并发清除
优点: 并发收集、低停顿
缺点:
- 虽然不会停顿、但是会降低吞吐
- 回收与工作线程并行,工作线程产生了新的垃圾,无法回收
- 标记-清除: 由于用的是标记清楚法,导致产生碎片,大对象存储可能引起新的GC
3.5 G1收集器(Garbage First)
相对于CMS, 基于标记-整理算法,不会产生碎片垃圾,其次比较青雀的控制停顿。
3.6 其他
Serial Old、Parallel Old, RTSJ
四、常见问题
内存溢出
分配给JVM内存,超出了系统分配的,系统不能满足需求。