参考原文:
https://blog.csdn.net/qq_33591903/article/details/82024257
https://blog.csdn.net/u014086926/article/details/52106589
JDK1.2之后,把对象的引用分为四种状态,即强引用、软引用、弱引用和虚引用。
目的:
- 可以让程序员通过代码的方式决定某些对象的生命周期;
- 有利于JVM进行垃圾回收;
1、强引用
开发中使用最多。
指创建一个对象并把这个对象赋给一个引用变量。
强引用声明格式:
Object obj = new Object();
String a = "abc";
只要某个对象与强引用关联,那么JVM在内存不足的情况下,宁愿抛出outOfMemoryError错误,也不会回收此类对象。
注 : 如果我们想要JVM回收此类被强引用关联的对象,我们可以显示地将str置为null,那么JVM就会在合适的时间回收此对象。
2、软引用
java中使用SoftRefence来表示软引用,如果某个对象与软引用关联,那么JVM只会在内存不足的情况下回收该对象。
垃圾收集线程会在虚拟机抛出OutOfMemoryError之前回收软可及对象,而且虚拟机会尽可能优先回收长时间闲置不用的软可及对象,对那些刚刚构建的或刚刚使用过的“新”软引用对象会被虚拟机尽可能保留。
利用这个特性,软引用可以用来做一些高速缓存。
软引用声明格式:
import java.lang.ref.SoftReference;
public class TestRef {
public static void main(String args[]) {
SoftReference<String> str = new SoftReference<String>(new String("abc"));
System.out.println(str.get());
//通知JVM进行内存回收
System.gc();
System.out.println(str.get());
}
}
输出:
abc
abc
由此可以看出,此时JVM内存充足,暂时还没有回收被软引用关联的对象。
注: 软引用适合做缓存,在内存足够时,直接通过软引用取值,无需从真实来源中查询数据,可以显著提升网站性能。当内存不足时,能让JVM进行内存回收,从而删除缓存,这时候只能从真实来源查询数据。
3、弱引用
java中使用WeakReference来表示弱引用。如果某个对象与弱引用关联,那么当JVM在进行垃圾回收时,无论内存是否充足,都会回收此类对象。
弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的
isEnQueued 方法返回对象是否被垃圾回收器标记。
弱引用声明格式:
import java.lang.ref.WeakReference;
public class TestRef {
public static void main(String args[]) {
WeakReference<String> str = new WeakReference<String>(new String("abc"));
System.out.println(str.get());
str.isEnQueued(); //返回是否被垃圾回收器标记为即将回收的垃圾
//通知JVM进行内存回收
System.gc();
System.out.println(str.get());
}
}
结果:
abc
null
可以看得出来,被弱引用关联的对象,总是会在下一次垃圾回收时被回收掉。
注1:System.out.println(str.get());有可能取不到str的值。这是因为我们在声明了弱引用之后,立即对其输出,而gc线程是一个优先级很低的守护线程,还来不及扫描该该对象所在的区域,即来不及对该对象的回收。如果我们在声明之后的很长时间后,再次get,是有可能get不到值的。
注2:第二个输出结果是null,这说明只要JVM进行垃圾回收,被弱引用关联的对象必定会被回收掉。不过要注意的是,这里所说的被弱引用关联的对象是指只有弱引用与之关联,如果存在强引用同时与之关联,则进行垃圾回收时也不会回收该对象(软引用也是如此)。
注3: 弱引用可以在回调函数在防止内存泄露。因为回调函数往往是匿名内部类,一个非静态的内部类会隐式地持有外部类的一个强引用,当JVM在回收外部类的时候,此时回调函数在某个线程里面被回调的时候,JVM就无法回收外部类,造成内存泄漏。在安卓activity内声明一个非静态的内部类时,如果考虑防止内存泄露的话,应当显示地声明此内部类持有外部类的一个弱引用。
4、虚引用
java中使用PhantomReference来表示虚引用。虚引用,虚引用,引用就像形同虚设一样,就像某个对象没有引用与之关联一样。若某个对象与虚引用关联,那么在任何时候都可能被JVM回收掉。虚引用不能单独使用,必须配合引用队列一起使用。
虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引
用。虚引用主要用于检测对象是否已经从内存中删除。
虚引用声明格式:
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
public class TestRef {
public static void main(String args[]) {
ReferenceQueue<String> queue = new ReferenceQueue<>();
PhantomReference<String> str = new PhantomReference<String>("abc", queue);
str.isEnQueued(); //返回是否从内存中已经删除
System.out.println(str.get());
}
}
结果:
null
可见使用get方法无法获取该对象的值
注1: 当垃圾回收器准备回收一个对象时,如果发现它与虚引用关联,就会在回收它之前,将这个虚引用加入到引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被回收,如果确实要被回收,就可以做一些回收之前的收尾工作。