概述

相关知识结构

Java GC

GC的大致流程

  1. 判断对象是否可回收(是否死亡)
  2. 合适的时候由具体的垃圾收集器执行回收操作

哪些内存需要回收?

堆内存的回收

1. 引用计数算法

给对象中添加一个引用计数器,每当有一个点引用它时,计数器的值就加1,当引用失效时,计数器减1。

优点:

  • 实现简单
  • 高效

缺陷:

  • 无法解决循环引用的问题

    循环引用:两个对象已经无法被访问,但是却相互引用着对方,导致他们的引用计数器都不为0,无法通知GC收集器回收他们。

2. 可达性分析算法

将一些列GC Roots的对象作为起始节点(树的根节点),不断向下搜索,走过的路径就称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连的时候(即:从GC Roots不可达),则该对象是不可用的,将被回收。

可作为GC Roots的对象:

  1. 虚拟机栈帧中本地变量表中引用的对象
  2. 方法区中类静态属性引用的对象
  3. 方法区中常量哦=引用的对象
  4. 本地方法栈中Native方法引用的对象

优点

  • 解决了引用计数算法中循环依赖的问题

缺点

  • 每次回收前,需要先确定GC ROOts

3. 四种引用类型

无论是引用计数算法还是可达性分析算法,都离不开“引用”。

强引用:只要引用还在,对象就永远不会被回收

  • Java程序中普遍存在的一种引用
  • 通过类似:
    Object obj = new Object();
    的操作生成的引用。

软引用:内存不够时就会被回收

  • 用来描述一些还有用但非必要的对象。
  • JDK 1.2之后,通过SoftReference类来实现软引用。

弱引用:下一次垃圾回收时就会被回收

  • 也是用来描述非必须的对象,但是强度较 软引用 更弱。
  • JDK 1.2之后,通过WeakReference类来实现弱引用。

虚引用:不会对对象的生存时间构成影响

  • 无法通过虚引用获取一个对象实例。
  • 唯一目的:在对象被回收时收到一个系统通知。
  • JDK 1.2之后,通过PhantomReference类来实现虚引用。

方法区的回收

常量池的回收

不存在相关引用即可回收。

类信息的回收

要同时满足一下三个条件:

  1. 类的所有实例都被回收(堆中不存在任何实例)
  2. 加载该类的ClassLoader已被回收
  3. 不存在该类的java.lang.Class对象的引用

如何回收

标记-清除 Mark-Sweep

通过对可回收的对象进行标记,再统一进行回收

标记-清除

优点

  • 简单

缺点

  • 效率低:标记和清除两个过程效率都不高
  • 会产生大量的内存碎片

    内存碎片:小而不连续的内存空间。内存碎片过多会导致较大对象分配时可用内存不足,不得不提前触发下一次垃圾回收,影响性能。

复制 Coping

每次只使用一半的内存区域,在触发回收时,将可用的数据复制到另一半空间中,并对当前这一半进行回收。

复制

优点

  • 实现简单:不用考虑内存碎片等问题、只需要移动对顶指针按序分配内存即可
  • 运行高效

缺点

  • 代价较大:内存缩小了一半
  • 存活率较高时,需要进行较多的复制操作,影响效率

标记-整理

通过对可回收的对象进行标记,将后面可用的对象整理到当前位置。
即:让所有的可用对象向前移动,紧凑到一块连续的空间中。

标记-整理

优点

  • 不会有额外的空间浪费
  • 不产生内存碎片

缺点

  • 效率较低

分代收集

根据对象的存活周期,将内存划分为几个不同的块,在每一个块中使用不同的垃圾回收算法。
是当前商业虚拟都采用一种算法。

分代收集

新生代

  • 对象存活时间较短的内存区域,每次回收时都有大批对象死去
  • 一般使用 复制算法 ,只需付出少量存活对象的复制成本就可以完成收集
  • 分为EdenFrom SurvivorTo Survivor三部分,其带小比例一般为8:1:1
    ①:EdenFrom Survivor复制到To Survivor
    ②:From SurvivorTo Survivor交换
    To Survivor变为From SurvivorFrom Survivor变为To Survivor

老年代

  • 对象存活率较高的内存区域。
  • 一般使用 标记-整理 或者 标记-清除 算法,可以不适用额外的空间进行分配担保。

什么时候回收

不同的垃圾收集器有不同的实现。
对于部分的收集器,收集器无法与工作线程同时运行,即存在 “Stop The World” 现象:所有工作线程都暂停,直至垃圾回收结束。
可以与工作线程同时运行的收集器:

  • CMS
  • G1