如果reference类型的数据中存放的数值是另外一块内存的起始地址,就称这块内存代表着一个引用。为了更好的控制对象的生命周期,提高内存利用率,JDK1.2 之后,java扩充了引用的概念,将引用分为
强引用/软引用/弱引用/和虚引用四种。
-
强引用(Strong Reference) :只要对象可达就不会被回收,哪怕抛出OOM
-
软引用(Soft Reference):内存不足的时候才回收
-
弱引用(Weak Reference):下次gc的时候就回收;
-
虚引用(Phantom Reference):跟踪对象什么时候被回收
1、强引用 Reference
-
类似于"Object obj = new Object()"这类的引用,只要垃圾强引用存在,垃圾回收器就不会回收掉被引用的对象;
示例:
//强引用
public class {
static Object obj = new Object();
public static void main(String[] args) {
Object obj2 = new Object();//一样不会被回收
Object obj1 = obj;
obj = null; //注意引用只是一个地址变量,obj=null, 但是 obj1 = new Object()还存在引用
System.gc();
System.out.println("gc 后:obj1-" + obj1);
System.out.println("gc 后:obj-" + obj);
}
}
回收的情况:
-
1、作用域结束;
-
2、不可达,复制为null;
2、软引用 SoftReference
-
当内存不够时回收
示例:
public class SoftReferenceTest {
public static void main(String[] args) {
Object obj = new Object();
//在程序发生oom前才会被回收;内存不足的时候才会被回收
//并且优先回收长时间空闲的对象
//适合非必须大对象的缓存;
SoftReference softReference = new SoftReference(obj);
System.out.println(softReference.get());
}
}
3、弱引用 WeakReference
-
强度比软引用更弱,被弱引用关联的对象只能存活到下一次垃圾回收gc之前,当发生gc,无论当前的内存是否充足,都会gc回收掉弱引用关联的对象;

使用示例:
@Data
public class Orange {
private String name;
public Orange(String name) {
this.name = name;
}
@Override
protected void finalize() throws Throwable {
System.out.println("finalized~ ");
super.finalize();
}
}
public class WeakOrange extends WeakReference<Orange> {
public WeakOrange(Orange referent) {
super(referent);
}
}
public class WeakReferenceTest {
public static void main(String[] args) {
Orange orange = new Orange("king"); //强引用
String str = "king-zz";
WeakOrange weakOrange = new WeakOrange(orange); //弱引用
orange = null;
WeakOrange weakOrange = new WeakOrange(str); //弱引用-str 此时str不会被回收,因为str在常量池中,gc不会清理常量池
str = null;
System.out.println("gc前 " + weakOrange.get());
System.gc(); // 发生gc
try {
sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("gc 后:" + weakOrange.get());
}
}
运行结果result:
gc前 Orange(name=king)
finalized~
gc 后:null
4、 虚引用 PhantomReference
-
引用基本不影响什么,做个标记,在垃圾回收前,处理一些事情。
实例:
跟踪对象什么时候会回收,只有在gc的时候,才会在虚引用队列里取到该值,判断回收前需要做什么。
public class PhantomRef {
public static void main(String[] args) throws InterruptedException {
Object obj = new Object();
ReferenceQueue queue = new ReferenceQueue();
//todo 必须是对象和队列一起使用才OK;
PhantomReference phantomReference = new PhantomReference(obj, queue);
//todo 这里获取的值永远为空,只有在gc的时候,才会在队列的取到这个对象的值,做一些资源的关闭清理;
System.out.println("phantomReference1 " + phantomReference.get()); //null
obj = null;
System.gc(); //gc前会将该对象放入到队列中,然后处理完后再回收
System.out.println("phantomReference2 " + phantomReference.get());
sleep(1000);
System.out.println("queue.poll " + queue.poll());
}
}
5、小结
引用让我们更好的控制对象的生命周期,更高效的利用内存,防止内存泄漏。
水滴石穿,积少成多。学习笔记,内容简单,用于复习,梳理巩固。