1.垃圾回收
1.1概念
在Java语言中,垃圾回收(Garbage Collection,GC)是一个非常重要的概念。
它的主要作用是回收程序中不再被使用的内存,Java提供的GC功能可以自动监测对象是否已经超过作用域从而达到自动回收内存的目的。即垃圾回收的是无任何引用的对象占据的内存空间而不是对象本身。
1.2任务
Java语言提供了垃圾回收器来自动检测对象的作用域,可自动地把不再被使用的存储空间释放掉。
具体而言,垃圾回收器主要负责三个事情
- 分配内存;
- 保证不再被使用的内存被释放掉;
- 保证被引用的对象不会被回收。
1.3方式
垃圾回收器通常是作为一个单独的低优先级的线程运行,不可预知的情况下对内存堆中已经死亡或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。
2.垃圾回收
要回收的垃圾:不可能在被任何途径使用的对象
找到这些对象的方法:
2.1引用计数法
给对象中添加一个引用计数器。
- 每当一个地方一用这个对象时,计数器值+1;
- 当引用失效时,计数器值-1。
任何计数值为0的对象就是不可能再被使用的对象。
Java中没有使用这种算法,因为这种算法很难解决对象之间相互引用的情况。
举例:
/**
* 虚拟机参数:-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.2可达性分析
这个算法的思想是:用过一系列成为“GC Root”的对象作为起始点,从这些节点向下搜索,搜索所走过的路径成为引用链。
当一个对象到GC Root没有任何引用链(即GC Roots到对象不可达)时,则证明此对象是不可用的。
Java中的GC Roots对象包括:
- 虚拟机栈(栈帧中的局部变量区,也叫作局部变量表)中引用的对象;
- 方法去中的类静态属性引用的对象;
- 方法区中常量引用的对象;
- 本地方法栈中JNI(Native方法)引用的对象。
GC Roots举例:
下图为GC Roots的引用链
由图可知,obj8、obj9、obj10都没有到GC Roots对象的引用链。
即便obj9和obj10之间有引用链,它们还是会被当成垃圾处理,可以进行回收。
2.2.1 GC停顿(的原因)
判断对象是否存活的可达性分析对时间的敏感还体现在GC停顿上。
因为可达性分析工作必须在一个能确保一致性的快照中进行,
- “一致性”的意思是指在整个分析期间整个执行系统看起来就像被冻结在某个时间点上,不可以出现分析过程中对象引用关系还在不断变化的情况。
- 不然的话可达性分析的结果就无法得到保证,这是导致GC进行时必须停顿所有Java执行线程的一个重要原因。
3.四种引用状态
JDK1.2之前,Java中引用的定义很传统:
如果引用类型的数据中存储的数值代表的是另一块内存的起始地址,就称这块内存代表着一个引用。
(定义很纯粹,但过于狭隘——一个对象只有被引用或者没被引用两种状态)
我们希望描述这样一类对象:
当内存的空间还足够时,则能保留在内存中;
如果内存空间再进行垃圾收集后还是非常紧张,则可以抛弃这些对苍。
JDK1.2之后,Java对引用的概念进行了扩展,将引用分为:强引用、软引用、弱引用、虚引用四种,这四种引用强度一次减弱。
1.强引用
Object obj=new Object();这类引用;
如果一个对象具有强引用,那垃圾回收器当内存不够时,宁愿抛出outofmemory错误也不会程序终止。
只要强引用还存在,垃圾回收器永远不会回收掉被引用的对象。
2.软引用
有些还有用但并非必需的对象。
如果一个对象具有软引用,如内存空间足够,垃圾回收器就不会回收它,如果内存不足,就会回收这些对象的内存(可以实现内存敏感的高速缓存,软引用可以和一个引用队列(ReferenceQueue)联合使用)
如果这次回收还没有足够的内存,才会抛出内存溢出异常。
Java中SoftReference表示软引用。
主要特点:
- 具有较强的引用功能。
- 只有当内存不够的时候,才进行回收这类内存;
- 因此在内存足够的时候,它们通常不被回收。
- 这些引用对象还能保证在Java抛出OutOfMemory 异常之前,被设置为null。
- 它可以用于实现一些常用图片的缓存,实现Cache的功能,保证最大限度的使用内存而不引起OutOfMemory。
3.弱引用
非必需对象。
被弱引用关联的对象智能生存到下一次垃圾回收之前。
垃圾回收器工作之后,无论当前内存