垃圾收集器及原理
垃圾收集器及原理
JVM垃圾收集器负责回收无用对象,以防止内存泄漏。常见的收集器有Serial、Parallel Scavenge、ParNew、Serial Old、Parallel Old、CMS和G1及ZGC等。 本文主要简单记录垃圾收集器常用的垃圾收集算法、串行以及并行垃圾收集器的相关知识。
GC算法
- 分代收集算法: 这种算法根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代。新生代中的对象一般存活时间较短,所以选择复制算法,而老年代中的对象存活时间长,空间大,所以选择标记-清理或者标记-整理算法。
- 复制算法: 这种算法将内存分为两块,每次只使用其中一块。当这一块内存用完后,就将还存活的对象复制到另一块上面,然后再把已使用的内存空间一次清理掉。这种算法的主要缺点是内存利用率只有50%。
- 标记-清除算法: 这种算法首先标记出所有需要回收的对象,然后进行清除。这种算法的主要缺点是效率不高,并且清除后会产生大量的内存碎片。
- 标记-整理算法: 这种算法是在标记-清除算法的基础上进行的改进,标记过程仍然与标记-清除算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
Serial收集器
Serial收集器是Java虚拟机(JVM)中最基本,也是历史最悠久的垃圾收集器。此收集器是一个单线程的收集器,它在进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束,这种机制被称为Stop-The-World(STW)。
Serial收集器的优点在于是单线程运行,没有线程交互的开销,对内存的消耗小,可以专心做垃圾收集,因此可以获得很高的单线程收集效益。缺点就是在垃圾收集过程中其他CPU资源被闲置,必须暂停其他所有的工作线程(STW),这会影响到应用程序的响应性能。
Serial Old收集器被用作Serial收集器的老年代版本,它同样是一个单线程收集器。它主要有两大用途:
- 在JDK1.5版本及以前的Parallel Scavenge收集器搭配使用
- 作为CMS收集器的后备方案
Serial收集器主要用于新生代的垃圾回收,采用的是复制算法。 Serial Old收集器使用的是标记-整理算法。
Parallel收集器
Parallel收集器是Serial收集器的多线程版本,除了使用多线程进行垃圾收集以外,其行为(参数控制、收集算法、回收策略等)和Serial相似。
Parallel收集器主要用于多核处理器的服务器中,旨在提高垃圾收集的吞吐量(高效的利用CPU),所谓吞吐量就是CPU中用于运行用户代码的时间与CPU总耗时的比值。在注重吞吐量以及CPU资源的场合,都可以优先考虑Parallel收集器配合Parallel Old收集器来进行垃圾收集(JDK1.8默认垃圾收集组合)。
Parallel Old收集器是Parallel收集器的老年代版本,同样是使用多线程来进行垃圾收集。Parallel采用的是复制算法。 Parallel Old收集器使用的是标记-整理算法。
ParNew收集器
ParNew垃圾收集器是一种用于新生代的并行垃圾回收器,与Parallel收集器类似,都是并行收集器。它的名字中的 “Par” 是 “Parallel” 的缩写,表示并行,而 “New” 表示它主要处理新生代的垃圾回收。
ParNew收集器的诞生主要是为了配合CMS(Concurrent Mark-Sweep)垃圾回收器一起使用,用于处理新生代的垃圾回收。这是因为在新生代中,回收次数频繁,使用并行方式更高效。此外,目前只有Serial和ParNew可以与CMS进行配合垃圾收集。