Java中的引用类似C++中的指针,用来指向一个对象,指向对象的变量叫做引用变量,除了8中基本类型,其他的类型都是引用类型,主要包括:类、接口、数组、枚举、注解。

主要分为四种引用:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference),引用强度依次减弱,生命周期也不一样。JVM的垃圾回收机制分别进行不同的处理。

强引用

最常见的一种引用,是将一个对象赋值给另一个引用变量,这个引用变量就是强引用,当一个对象被强引用变量引用时,一直是可到达状态,GC是不能回收的,因此也是导致内存泄漏的常见原因之一,比如:

1
2
3
4
5
6
7
Object obj1 = new Object();
// 强引用
Object obj2 = obj1;
obj1=null;
System.gc();
System.out.println("对象1:"+obj1);
System.out.println("对象2:"+obj2);

软引用

如果一个对象只具有软引用,那就类似于可有可物的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存 空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。 软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联 的引用队列中。
使用SoftReference类实现。
栗子代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 不充足的内存空间,则会回收
* -Xmx5m,先申请一个2M的被软引用,在申请一个3M的
*/
public static void softReferenceNotEnoughMem(){
byte[] bytes = new byte[2*1024*1024];
// 软引用
SoftReference<Object> ref1=new SoftReference<>(bytes);
// 置空ref1也不会回收
bytes=null;
System.out.println("对象1:"+bytes);

System.out.println("==== 空间很足 ====\n软引用对象:"+ref1.get());
byte[] bytes3m=new byte[3*1024*1024];
System.out.println("==== 空间不足 ====\n软引用对象:"+ref1.get());
}
/**
输出结果为:
对象1:null
==== 空间很足 ====
软引用对象:[B@14ae5a5
==== 空间不足 ====
软引用对象:null
*/

弱引用

弱引用也是用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。
使用WeakReference类实现,比软引用的生命周期更短,只要GC发生就会回收。
如Java中的WeakHashMap类,当key置空后,下一次垃圾回收后,对应的键值对就会被回收。

1
2
3
4
5
6
7
8
9
10
 private static void weakMap(){
WeakHashMap<String,String> map = new WeakHashMap<>();
String key = new String("key1");
String value="val1";
map.put(key,value);
key=null;
System.out.println("回收前的弱引用:"+map.get("key1")); // val1
System.gc();
System.out.println("回收后的弱引用:"+map.get("key1")); // null
}

虚引用

虚引用,顾名思义,就是形同虚设,与其他几种引用都不太一样,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。
如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收,它不能单独使用也不能通过它访问对象,虚引用必须和引用队列(RefenenceQueue)联合使用。
虚引用的主要作用是跟踪对象垃圾回收的状态。仅仅是提供了一种确保对象被 finalize 以后,做某些事情的机制。PhantomReference 的 get 方法总是返回 null,因此无法访问对应的引用对象。其意义在于说明一个对象已经进入 finalization 阶段,可以被 GC 回收,用来实现比 finalization 机制更灵活的回收操作。