Java中的四种引用类型之强引用、软引用、弱引用和虚引用

Java中有一个java.lang.ref.*包,该包提供了引用对象类,支持在某种程度上与垃圾回收器之间的交互(通过引用对象类判断对象被垃圾回收器处理的状态)。  

引用的抽象接口:java.lang.ref.Reference
Reference就是引用的意思,Java中的引用从垃圾回收的角度来看分为:
强引用(java.lang.ref.FinalReference)
软引用(java.lang.ref.SoftReference)
弱引用(java.lang.ref.WeakReference)
虚引用(java.lang.ref.PhantomReference)
这四种引用强度依次减弱,而且一个对象可以同时拥有多种引用, 并且可以通过Reference.get()方法获取。

1)强引用
强引用是Java中最常见、使用最多的引用,把一个对象赋给一个引用变量的普通引用就是强引用。例如:
Object o = new Object();
o就是一个强引用,它处于可达状态,强引用不会被JVM垃圾回收,即使内存不够抛出OutOfMemoryError也不会被回收,即使该对象以后永远都不会被用到JVM也不会回收。因此强引用是造成OOM的主要原因之一。

注意:强引用在Java中没有对应的实现类,总结而言,强引用有如下特点: 

强引用可以直接访问目标对象

强引用所指向的对象在任何时候都不会被JVM回收

强引用可能导致内存泄漏

2)软引用
软引用是Java中一个类,需要用SoftReference类来实现,它保存的引用只有在内存不够的时候才会被JVM回收,言外之意就是当系统内存足够时它不会被回收,当系统内存空间不足时它才会被回收,所以软引用通常用在对内存敏感的程序中(常用来作缓存的设计)。

软引用可以和ReferenceQueue一起使用,当SoftReference的Referent被回收以后,这个SoftReference会被自动加入到ReferenceQueue中。也就是说,当垃圾回收器决定对软引用对象进行回收时,会先清空它的SoftReference,SoftReference的get()方法将会返回null,然后再调用对象的finalize()方法,并在下一轮GC中对其真正进行回收。

public class Student {
	String id;
	String name;
	String age;

	//getter setter略
}
package com.xf.web;

import java.lang.ref.Reference;  
import java.lang.ref.ReferenceQueue;  
import java.lang.ref.SoftReference;  
  
 
public class SoftReferenceTest {  
    public static void main(String[] args) throws InterruptedException {  
        Student a = new Student();  
        a.setName("张三");
        ReferenceQueue<Student> rq = new ReferenceQueue<Student>();  
        SoftReference<Student> weak = new SoftReference<Student>(a, rq);  
        a = null;  
        System.out.println(weak.get().getName()); //张三
        System.gc();   
        System.out.println(weak.get().getName()); //虽然gc 但是内存充足 仍然输出张三  
        cleanHeapFunction(); //调用该方法 让内存不足 
        System.out.println(weak.get()); // null 
        Reference<? extends Student> rs = rq.poll(); //可以获取实例 
        System.out.println(rs);  // java.lang.ref.SoftReference@19e0bfd
        System.out.println(rs.get());  //null
    }  
      
    /** 
     * 使用所有堆 让内存不足 
     */  
    public static void cleanHeapFunction(){  
        try{  
            StringBuffer bf = new  StringBuffer();  
            for(int i=0;i<10000000000L;i++){  
                bf.append(i);  
                bf.append(bf);  
            }  
        }catch(Error e){  
              
        }  
    }  
}  

所以,软引用的特点可以总结如下: 

软引用使用get()方法取得对象的强引用从而访问目标对象

软引用所指向的对象按照JVM的使用情况(Heap内存是否临近阈值)来决定是否回收

软引用可以避免Heap内存不足所导致的异常

3)弱引用
弱引用需要用WeakReference类来实现,它比软引用的生存期更短,只要垃圾回收机制运行,不考虑内存实际占用,不管JVM的内存空间是否充足,总会回收该对象占用的内存,所以在某些短生命周期的对象也是适合做缓存的。  

WeakReference是弱于SoftReference的引用类型。弱引用的特性和基本与软引用相似,区别就在于弱引用所指向的对象只要进行系统垃圾回收,不管内存使用情况如何,永远对其进行回收(get()方法返回null)。 

import java.lang.ref.Reference;  
import java.lang.ref.ReferenceQueue;  
import java.lang.ref.WeakReference;  
  
public class WeakReferenceTest {  
    public static void main(String[] args) throws InterruptedException {  
        Student a = new Student();  
        a.setName("张三");
        ReferenceQueue<Student> rq = new ReferenceQueue<Student>();  
        WeakReference<Student> weak = new WeakReference<Student>(a, rq);  
        a = null; //定义a=null 但是我们不使用此实例 
        System.out.println(weak.get().getName()); //弱引用对象 输出张三  
        System.gc(); //调用GC  
        Thread.sleep(1000);  
        Reference<? extends Student> rs = rq.poll();  
        System.out.println(rs.get()); //调动gc 对象被回收 所以输出null  
    }  
    
}  

所以,弱引用对象的特点可以总结为:

弱引用使用get()方法取得对象的强引用从而访问目标对象

一旦系统内存回收,无论内存是否紧张,弱引用指向的对象都会被回收

弱引用也可以避免Heap内存不足所导致的异常

4)虚引用
虚引用需要PhantomReference类来实现,PhantomReference是所有“弱引用”中最弱的引用类型。

不同于软引用和弱引用,虚引用无法通过get()方法来取得目标对象的强引用从而使用目标对象,观察源码可以发现get()被重写为永远返回null。所以虚引用不会影响对象的生命周期,主要作用是跟踪对象被垃圾回收的状态(对象生命周期的一个标记),他必须与ReferenceQueue一起使用。因为它的作用就是在对象被JVM决定需要GC后, 将自己enqueue到RQ中. 他通常用来在一个对象被GC前作为一个GC的标志,以此来做一些finalize操作。

需要注意的是,虚引用在实际使用中不太普遍。 

发布了224 篇原创文章 · 获赞 34 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/weixin_39309402/article/details/104908289