Java垃圾回收(GC)机制
标签(空格分隔): java虚拟机
垃圾回收的是什么?
我们需要回收的对象是那些不可能再被任何途径使用的对象
如何确定对象不再被引用?
1、引用计数法:
在对象中添加一个引用计数器,每当一个地方引用这个对象一次,计数器值就+1;当引用失效的时候就-1。当某个时候计数值等于0的时候,该对象将不再被引用
该算法实现简单,判定效率高,在大多数的情况下是个不错的算法。但是它的大缺点就是解决不了对象之间相互引用的问题
/**
* 虚拟机参数:-verbose:gc
*/
public class ReferenceCountingGC
{
private Object instance = null;
private static final int _1MB = 1024 * 1024;
/** 这个成员属性唯一的作用就是占用一点内存 **/
private byte[] bigSize = new byte[2 * _1MB];
public static void main(String[] args)
{
ReferenceCountingGC objectA = new ReferenceCountingGC();
ReferenceCountingGC objectB = new ReferenceCountingGC();
objectA.instance = objectB;
objectB.instance = objectA;
objectA = null;
objectB = null;
System.gc();
}
}
运行结果:
[GC 4417K->288K(61440K), 0.0013498 secs]
[Full GC 288K->194K(61440K), 0.0094790 secs]
从运行结果看,两个对象相互引用,但是虚拟机还是把两个对象回收掉了,这说明虚拟机不是通过引用计算法来判定对象是否存活。
2、可达性算法分析
这种算法的基本思想是通过一系列称为“GC Roots”的对象作为起点,从这些起点向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链的时候,就证明此对象是不可用的。
java中可以作为GC Roots的对象包括:
虚拟机栈中引用的对象
方法区中静态属性引用的对象
方法区中常量引用的对象
本地方法栈中JNI(Native方法)引用的对象
引用状态:
强引用、软引用、弱引用、虚引用
在JDK1.2以前,java对引用的定义就是一个对象只有两种状态(被引用和未被引用);但是现在我们的做法是当内存空间足够的时候,对象保留着;如果内存空间进行垃圾回收后还是很紧张,则可以抛弃这些对象---JDK1.2之后对引用概念的扩充。
垃圾回收算法
1、标记-清除算法
2、复制算法
3、标记-整理算法
4、分代收集算法(就是对上面的三种算法进行整合,在合适的条件下使用对应的算法)
垃圾收集器
垃圾收集器是上面的理论的具体体现。我们使用的HotSpot虚拟机包含的垃圾收集器如下图:
上面有7中收集器,分为两块,上面为新生代收集器,下面是老年代收集器。两者之间有线的可以搭配使用
并发和并行
并行(parallel):多条垃圾收集器线程并行工作,但此时用户仍然处于等待状态
并发(Concurrent):用户与垃圾收集器线程同时执行,用户程序在继续运行,而垃圾收集器程序运行在另一个CPU上。
Serial(串行GC)收集器
serial收集器是一个新生代收集器,单线程执行,使用复制算法。它只会使用一个CPU去收集垃圾,而且其他的工作线程必须等待,知道它收集完成。
ParNew(并行GC)收集器
ParNew收集器就是Serial收集器的多线程版本,使用复制算法。除了使用多条线程进行垃圾收集之外,其余行为与Serial收集器一样。