浅谈java垃圾回收

Sep 4, 2015


当我刚接触java这么语言的时候,老师就开始说,java能在这么多语言中脱颖而出,成为广大程序猿吃饭生存的语言,其中一个优点就是他有垃圾回收器,让我们能专注业务逻辑,而不是像C或者C++这种,当一块内存不使用的时候,要free或者delete一下。但是我们却很难真正理解他,因为他的存在从来都是默默的,只有内存泄漏出问题的时候,我们可能才会真正有兴趣的去研究他。 垃圾回收器是JVM的一个优秀的组成部分,在研究垃圾回收之前,我们先去看看常用的垃圾回收的算法。

常用的垃圾回收算法


  1. 引用计数法
  2. 标记清除法
  3. 复制算法
  4. 标记压缩法
  5. 分代算法
  6. 分区算法

下面开始依次分析这几种算法的优缺点,以及jvm的垃圾回收器到底使用的是哪一种。 1.引用计数法,非常简单,比如一个对象被引用了,他的计数器就加1,当引用失效,计数器减1,所以当一个对象计数器为0的时候,那就说明它没被引用,需要被回收。缺点很明显,当对象之间交叉引用的时候,计数器永不为0,则永不会被回收,因而jvm并没有使用这个算法。
2.标记清除算法,垃圾回收算法的基础,用到了树这个结构,从一个根节点进行标记,当根节点到底不了这个对象的时候,就是告诉JVM这个对象需要回收,缺点就是,回收后可能会产生很多的内存碎片。
3.复制算法,将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收的时候,存活对象使用的内存复制到未使用的的内存中,再清除正在使用的内存,相当于交换一个正在使用的内存和未使用的内存。有点很明显,效率高且没有碎片,但是它只能每次使用一半的内存,在java新生代的串行垃圾回收器中使用了这个算法。
4.标记压缩法:这个是老年代的回收算法,他的标记内存使用和标记清除算法是一样的,但是他并不是里面在垃圾回收的清理这个对象,二是把所有的存活对象压缩到内存的一端,再清理边界外的空间,这样就没有了内存碎片的产生。
5.分代算法:分代很简单,就是将java的内存对象分为几代,根据每个区域的特点,使用不同的回收算法,提高垃圾回收的效率。一般java的新生代使用复制算法,老年代使用标记清除算法或者标记压缩法。
6.分区算法:分区算法是将挣个堆空间划分成连续的不同小区间,每个小区间独立使用,独立回收。这样垃圾回收的时候,会针对每个小区间回收,频率高但是停顿少。

垃圾回收器


JVM中,垃圾回收器实际上有多种,每种针对不同的使用场景来发挥它特有的优势,最大程度的提升机器的性能。 主要有以下几种垃圾回收器:


  1. 串行回收器
  2. 并行回收器
  3. CMS回收器
  4. G1回收器

下面简要的介绍这几种回收器的特点。 1:串行回收器:(1).单线程进行垃圾回收;(2).独占式的垃圾回收。他的缺点非常明显,垃圾回收的时候,会停止目前所有正在操作的线程,因而会根据时间的长短有明显的停顿现象,在现代的JVM中,这种已经基本上不在使用。
2:并行回收器:使用了多线程进行回收,对于服务器领域,性能比较强劲的机器来说,并行回收器可以有效的缩短垃圾回收的时间,但是他并没有解决当垃圾回收的时候,正常服务线程需要停止的情况,可能根据实际情况,还是会有停顿的现象。
3.CMS回收器:全称为Concurrent Mark Sweep的缩写,即并发标记清除,它主要是关注于系统的停顿时间,力求让系统的停顿时间降到最低,他使用的是标记清除算法,同时也是一个更加复杂的并行垃圾回收器。它的主要工作步骤为:初始标记、并发标记、预清理、重新标记、并发清除和并发重置。他的初始标记和并发标记是独占系统资源的,但是后面的操作是和用户的线程是一起执行的,所以并不是独占的垃圾收集,可以大大降低服务停顿的时间。但是它的缺点还是标记清除算法会产生内存的碎片,虽然它有碎片整理的方案。
4.G1回收器:全称为Garnage-Frist,G1回收器是JDK1.7中最新的垃圾回收器,他的回收策略和以前的不同,它使用了分区的算法,主要有以下的一些特点:

  • 并行性:G1在回收期是多个GC线程进行,利用机器的多核计算能力。
  • 并发性:G1有与应用交替执行的能力,部分工作可以和应用同时进行,因此一般来说,不会在整个回收期间堵塞应用程序。
  • 分代GC:G1有效的分开了年轻代和老年代的回收算法,
  • 空间整理:在垃圾回收的过程中,会适当的对对象移动,每次回收都会有效的复制对象,减少空间碎片。
  • 可预见性:G1使用了分区算法,因而回收的时候会只选取部分区域进行垃圾的回收,缩小了回收的范围。 G1的收集过程主要分为下面的阶段:新生代的GC;并发标记周期;混合收集;根据实际,可能会full GC。

JVM在垃圾回收这部分还有很多比较高深的算法和方案,因而在现代的领域中,我们可以越来越最大化的使用机器的性能,并更加精确的定位到相关性的问题。
(ps:本文主要摘抄于《深入理解java虚拟机》和《实战Java虚拟机》,仅限个人笔记,没有任何商业用途!)