文章目录
- 1. 强引用
- 2. 软引用(SoftReference)
- 3. 弱引用(WeakReference)
- 4. 虚引用(PhantomReference)
- 5. 总结
java中对象引用分为强、软、若、虚4中引用,其中强引用就是普通的new一个对象,软引用、弱引用、虚引用都是继承自抽象类Reference。
1. 强引用
程序代码中最常见的引用,比如Persion persion = new Persion(),无论任何情况下,只要强引用关系还在,强引用的对象是可触及的,垃圾回收器就不会回收掉被引用的对象。
如果领强引用关系显示设置null,那么在垃圾回收时就有可能会被回收,具体的回收时机要看垃圾收集策略。正是因为只要强引用的关系存在,就不会被GC,因此强引用是造成java内存泄漏的主要原因之一。
只要强引用关系还在,即使程序抛出OOM异常,不会回收强引用的对象。
例如
String str = new String("hello world");
其中局部变量str指向了堆中的String实例,通过str就可以操作该实例,因此str就是String实例的强引用。
2. 软引用(SoftReference)
软引用关系存在时,如果此时由于内存不足,则会发生GC进行垃圾对象回收,此时是不会回收软引用对象的,因为软引用关系还在,但是当GC后,内存还是不足以分配对象,此时会进行第二次GC,此时会回收掉软引用对象,如果即使回收掉软引用对象内存还是不足,则会发生内存溢出。
软引用是用来描述一些还有用,但非必须的对象。比如高速缓存就是用到软引用,如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉缓存,保证程序不至于崩溃。
示例一如下
public static void main(String[] args) {
/*persion为强引用*/
Persion persion = new Persion(1, "lzj", 30);
/*建立persion的软引用*/
SoftReference<Persion> reference = new SoftReference<>(persion);
/*令强引用为null,以便垃圾回收时进行回收*/
persion = null;
/*获取软引用的对象*/
System.out.println(reference.get()); //Persion{id=1, name='lzj', age=30}
}
示例二如下:
软引用在构造引用时也可以指定一个引用队列,当软引用关联的对象被回收时,就会把回收的软引用对象加入到指定的引用队列中,通过这个队列可以跟踪软引用关联对象回收情况。注意回收的是软引用关联的对象,加入到软引用队列中的是软引用对象
public static void test2() throws InterruptedException {
Persion persion = new Persion(1, "lzj", 30);
ReferenceQueue<Persion> queue = new ReferenceQueue<>();
SoftReference<Persion> reference = new SoftReference<>(persion, queue);
System.out.println("软引用对象为:" + reference);
/*垃圾回收之前,通过软引用可以获取对象的关联对象*/
System.out.println(reference.get());
persion = null;
System.gc();
Thread.sleep(1000);
System.out.println(reference.get());
/*运行之后,该句代码一直阻塞,表示没有软引用关联对象被回收,
* 调用队列的remove方法,当有一个软引用关联对象被回收时,该方法才会返回,否则就一直阻塞*/
Reference<? extends Persion> referenceGC = queue.remove();
if (referenceGC == null){
System.out.println("说明没有GC,或者GC后,内存空间依然充足,不会回收软引用关联的对象");
}
}
运行结果如下:
软引用对象为:java.lang.ref.SoftReference@383534aa
Persion{id=1, name='lzj', age=30}
Persion{id=1, name='lzj', age=30}
3. 弱引用(WeakReference)
弱引用也是用来表示一些非必须的对象,被弱引用关联的对象只能生存到下一次垃圾回收器发生为止。GC发生时,不管堆空间内存是否充足,都会回收掉弱引用关联的对象。
弱引用与软引用一样,都非常适合来保存那些可有可无的缓存数据。使用弱引用或软引用后,当系统内存不足时,这些缓存数据会被回收,不会导致内存溢出;当资源充足时,缓存数据可以长时间存在,提高程序执行效率。
示例一如下:
public static void test1(){
Persion persion = new Persion(1, "lzj", 30);
WeakReference<Persion> reference = new WeakReference<>(persion);
persion = null;
System.out.println(reference.get()); //Persion{id=1, name='lzj', age=30}
}
示例二如下:
弱引用和软引用一样,在构造引用时也可以指定一个引用队列,当弱引用关联的对象被回收时,就会把回收的弱引用对象加入到指定的引用队列中,通过这个队列可以跟踪弱引用关联对象回收情况。注意回收的是弱引用关联的对象,加入到弱引用队列中的是弱引用对象
public static void test2() throws InterruptedException {
Persion persion = new Persion(1, "lzj", 30);
/*垃圾回收的弱引用队列*/
ReferenceQueue<Persion> queue = new ReferenceQueue<>();
WeakReference<Persion> reference = new WeakReference<>(persion, queue);
System.out.println("弱引用对象为:" + reference);
persion = null;
/*垃圾回收前,弱引用关联的persion对象没被回收,可以获取到*/
System.out.println("垃圾回收前:" + reference.get());
/*强制执行GC*/
System.gc();
/*程序睡眠一段时间,以便执行GC*/
Thread.sleep(1000);
/*垃圾回收后,弱引用关联的persion对象被回收了,获取不到了*/
System.out.println("垃圾回收后:" + reference.get());
Reference<? extends Persion> persionGC;
while ((persionGC = queue.remove()) != null){
/*垃圾对垒中的persionGC就是前面的reference弱引用对象,而reference是对persion的弱引用,由此可见垃圾回收了persion对象,
* 注意是回收的弱引用关联的对象,即persion对象
* */
System.out.println("垃圾回收队列中回收的弱引用:" + persionGC);
break;
}
}
输出如下:
弱引用对象为:java.lang.ref.WeakReference@74a14482
垃圾回收前:Persion{id=1, name='lzj', age=30}
垃圾回收后:null
垃圾回收队列中回收的弱引用:java.lang.ref.WeakReference@74a14482
4. 虚引用(PhantomReference)
虚引用也称为幽灵引用或者幻影引用,是引用类型中最弱的一个。如果一个对象仅持有虚引用,那么它和几乎内有引用是相同的,只要有GC发生,随时会被回收掉。因此一个对象是否持有虚引用,完全不会决定对象的声明周期。
虚应用和前面几种引用不同,无法通过get方法获取关联的对象。为一个对象设置需饮用关联唯一目的在于跟踪垃圾回收过程。比如能在这个对象被垃圾回收器回收时收到一个系统通知。由于虚引用可以跟踪对象回收时间,因此,可以将一些资源释放操作放置在虚引用中执行和记录。
虚引用与前面引用另一个区别就是,虚引用必须与引用队列一起使用。当垃圾回收器准备回收一个对象时,如果发现他还有虚引用就会在回收对象后,将这个虚引用加入到引用队列,以便通知应用程序对象回收情况。
示例如下
```java
public class PhantomReferenceDemo {
public static Persion persion;
public static ReferenceQueue<Persion> queue;
public static void main(String[] args) {
QueueThread queueThread = new QueueThread();
/*设置守护线程,main线程结束后,queue线程也自动结束*/
queueThread.setDaemon(true);
queueThread.start();
persion = new Persion(1, "lzj", 0);
queue = new ReferenceQueue<>();
PhantomReference<Persion> reference = new PhantomReference<>(persion, queue);
persion = null;
System.gc();
}
public static class QueueThread extends Thread{
@Override
public void run() {
while (true){
if (queue != null){
Reference<? extends Persion> gcObject = null;
try {
gcObject = queue.remove();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (gcObject != null){
System.out.println("GC时,gcObject虚引用对象关联的对象被回收了");
}
}
}
}
}
}
5. 总结
强引用:引用关系存在,即可达性分析后为有效对象,就不会被回收,即使发生OOM;
软引用:内存不足时,回收软引用的关联对象;
弱引用:GC时,只要发现了弱引用,就回收弱引用关联对象;
虚引用:虚引用主要是用来做对象回收跟踪的。