一.GC作用范围
java中内存使用时要不断的清理,以避免内存溢出,内存垃圾的清理我就叫做java的GC,即指
垃圾收集并清理内存。说到java虚拟机不得不先说一下java虚拟机的分区,来指出GC时会涉及到那些分区。
java虚拟机分区图如下(盗了一张图,嘻嘻):
由上图可以看出java虚拟机中方法区和堆事线程间共享,其他分区是线程私有的。
方法区中存放的是存储已被虚拟机加载的类信息、常量、静态变量和即时编译器编译后的代码等数据;堆中存放的是对象的实例。
GC时回收的分区是方法区和堆,回收类型如下:
1.回收堆中没有被引用的对象
2.回收方法区中无用的常量和类(没被应用的类、该类中所有对象都已被回收、加载该类的class loader被回收)
目前GC使用的是分代收集算法,后面有讲解。
二.GC分类
1.Minrc GC
是对新生代区进行回收,由于新生代是大面积回收,一般采用复制回收算法
2.Full GC
当老年代区满了,触发全部,一般采用标记-整理算法
三.GC回收时机
- 当我们主动调用system.gc()时会触发Full GC
- 当新生代eden区满的时候会触发MinroGC
- 当老年代区满的时候会触发Full GC
四.GC垃圾收集方法
1.标记-清除算法
主要分为两个阶段
- 标记阶段:先标记可回收的对象
- 清除阶段:清除标记过程中可回收的对象
缺点:标记-清除算法是最基础的算法,不算效率很低并且在经历过一次标记-清除算法后,会产生很对不连续的内存空间,当申请较大的内存空间时没有足够大的连续内存空间用于分配,会导致再触发内存回收。
2.复制算法
会将内存空间分为两块,每次只使用一个区域。当出发GC的时候会遍历当前区域并将当前区域的存活对象复制到另一个区域,然后将当前区域全部清除。
优点:当存活对象较少时,复制算法的效率较高
缺点:
- 内存空间利用率较低,已使用一半的空间
- 当存活对象较多时,复制效率会大大降低
场景:一般用于分代收集算法中的新生代分区的收集
3.标记-整理算法(压缩算法)
主要分为两个阶段
- 标记阶段:先标记可回收的对象
- 整理阶段:清除标记过程中可回收的对象,然后将存活的对象进行整理,使存活对象连续排列,空出连续的可用内存空间
优点:可以空出连续的的可用内存空间,再申请大内存时减少了GC次数
缺点:效率低
场景:一般用于分代收集算法中的老生代分区的收集(老年代区域回收频率相对较低)
4.分代收集算法
分为新生代、老年代、永久代
新生代、老年代位于堆中
永久代存在于方法区中
新生代:
分为eden、form survivor、to survivor三个区,新生代区主要使用复制算法,始终有一个survivor区是空闲的。
复制算法:创建对象实例申请内存时,先将eden区和其中一个survivor区的存活对象复制到另一个survivor区,然后清理所有不可达对象,当eden区和某一个survivor区的存活对象空间大于另一个survivor区大小时,将炒过的部分放入到老年代的中。
注:新生代中如果多次清除还存活(一般15次),达到一定次数时也会将该对象放到老年代。
老年代:
当老年代满的时候会触发FullGC,一般采用标记-清除或标记-整理,标记需要清除的对象后将其清除。
持久代(永久代 perm)
按照内存存储的数据的生命周期,方法区也被称为持久代。表示此空间很少被回收,但是不表示不会被回收。
持久代的回收有两种:
- 常量池中的常量,常量如果没有被引用则可以被回收
- 无用的类信息(同时满足以下条件)
-
- 1. 类的所有实例都已经被回收了
- 2. 加载类的ClassLoader已经被回收
- 3. 类对象的class对象没有被引用(即没有通过反射引用该类的地方)
五.finalize方法
对象的状态分为可达、不可达、unfinalized、finalizable、finalized
可达:GcRoot引用链可以达到当前对象
不可达:GcRoot引用链可以达到当前对象
unfinalized: 新建对象会先进入此状态,GC并未准备执行其finalize方法,因为该对象是可达的
finalizable:当前对象不可达,已被标记,并进入清除队列,即将被调用finalize方法
finalized:当前对象已经调用过finalize方法
若不想对象被回收,可以在finalize方法中重新建立引用。
注:finalize方法只会被调用一次
六.判断对象是否需要回收的方法
1.引用计数算法
给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的,这就是引用计数算法的核心。
缺点:当不可达的两个对象互相引用时,引用计数永远大于0,不会被清除,所以此方法有漏洞,使用可达性分析法
2.可达性分析法
是GcRoots为起点,开始寻找引用链,是数据结构中图中的可达,寻找所有可达路径后,将不可达的对象清除掉。
不可达对象包括:
- 虚拟机栈中的引用对象
- 方法区中的常量
- 本地方法栈JNI引用的对象
七.引用类型
- 强引用
创建对象实例时,即为强引用,GC垃圾回收时不会被清除,生命周期很长。
- 软引用
softReference,用来描述有用非必须对象,在内存不足时,才会清除软引用关联的对象。
- 弱引用
Java中的类WeakReference表示弱引用。用来描述非必须对象,生存周期为创建到下次垃圾回收。
- 虚引用
虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是在这个对象被垃圾回收器回收时收到一个系统通知。