java中的引用分为4种,分别是:1.强引用;2.软引用;3.弱引用;4.虚引用。四种引用分别有各自的特点,下面分别通过代码对四种类型的引用进行一下测试。

1.强引用

  强引用是我们平时最常用的一种引用类型。在对象被引用的时候,不会被gc的垃圾回收器回收。当没有引用时,堆中对象会被回收。

  示范代码:

 1 /**
 2  * 验证垃圾回收机制类
 3  * @author 
 4  *
 5  */
 6 public class M {
 7     // 重写finalize 方法,该方法是Object对象的方法,在对象被回收时执行。
 8     // 平时开发不建议在该位置写代码,容易导致OOM问题
 9     @Override
10     protected void finalize() {
11         System.out.println("finalize");
12     }
13 }
验证类
 1 import java.io.IOException;
 2 /**
 3  * 强引用 普通的引用
 4  * 
 5  * 栈里的小m指向堆里的M对象,这个引用叫做强引用,只有没有任何引用指向对象的时候,对象才会被垃圾回收器回收
 6  * @author Lys
 7  *
 8  */
 9 public class T01_NormalReference {
10     public static void main(String[] args) throws IOException {
11         M m = new M();
12         m=null;
13         System.gc();
14         
15         System.in.read();
16     }
17 }

运行结果:

finalize

// 说明引用在被置为null 后,在系统gc的时候,对象被垃圾回收器回收了 

2.软引用

  只被软引用所引用的对象,会在jvm内存不够用的时候,被垃圾回收器回收。通过下面的测试代码我们可以看出:在m刚被定义的时候,这个时候m还是可以get到值的,然后调用系统gc,m对象也没有被垃圾回收器回收。但是当定义其他对象使内存不够用的时候,该对象就被回收掉了。该引用适用场景:一个比较大的缓存对象,经常需要读取。当系统空间足够的时候,就将其缓存在jvm中,当可用空间不足的时候,就将其回收掉。

  示范代码:

 1 /**
 2  * 软引用
 3  * 
 4  * 软应用内的对象会随着空间不够用而消失,一般应用于缓存。
 5  * @author Lys
 6  *
 7  */
 8 public class T02SoftReference {
 9     public static void main(String[] args) {
10         SoftReference<byte[]> m = new SoftReference<>(new byte[1024*1024*10]);
11 
12         System.out.println(m.get());
13         System.gc();
14         try {
15             Thread.sleep(500);
16         } catch (Exception e) {
17             e.printStackTrace();
18         }
19         System.out.println(m.get());
20         byte[] b = new byte[1024*1024*3];
21         byte[] b1 = new byte[1024*1024*3];
22         System.out.println(m.get());
23     }
24 }

  代码执行参数:-Xmx20M

  代码执行结果:

[B@15db9742
[B@15db9742
null

// 前两个打印输出证明在内存足够的情况下不会被回收,第三个输出表示,当内存不足时,软引用的对象就被垃圾回收器回收了

3.弱引用

  只有弱引用引用的对象在遇到垃圾回收器执行垃圾回收的时候,就会被回收。弱引用的应用场景:ThreadLocal 对象在调用set方法,在存储对象的时候。本身将当前线程局部变量对象作为key值,存入线程的ThreadLocalMap中,被set的值作为ThreadLocalMap的value。jdk源代码如下:

    static class ThreadLocalMap {

        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

  这里的super(key)创建了一个弱引用,当ThreadLocal 对象在栈中的引用消失后,这个对象就会被垃圾回收器回收,而不必担心出现内存泄漏问题。

示范代码:

/**
 * 验证垃圾回收机制的对象
 * @author 
 *
 */
public class M {
    // 重写finalize 方法,该方法是Object对象的方法,在对象被回收时执行。
    // 平时开发不建议在该位置写代码,容易导致OOM问题
    @Override
    protected void finalize() {
        System.out.println("finalize");
    }
}
验证对象
import java.lang.ref.WeakReference;
import java.util.WeakHashMap;
/**
 * 弱引用 垃圾回收器看到后就回收 ,,就会被回收
 * 应用场景:ThreadLocal 解决内存泄漏问题 ,但是用户自己创建的value还存在,所以tl中创建的内容,在tl不用以后,要进行remove操作。
 * @author Lys
 *
 */
public class T03_WeakRefernce {
    public static void main(String[] args) {
        WeakReference<M> m = new WeakReference<M>(new M());
        System.out.println(m.get());
        System.gc();
        System.out.println(m.get());
        
       //  ThreadLocal<M> tl = new ThreadLocal<>();
        // tl.set(new M());
        // tl.remove();

    }
}

代码执行结果:

reference.M@15db9742
null
finalize

4.虚引用

  虚引用在jvm 中没有内存,用于管理在虚拟机之外的内存。如下图所示,虚引用必须当我们的虚拟机需要管理一块不存在于jvm的内存时,需要跟踪对象的垃圾回收状态,如果对象被回收了,那么将该对象的引用放入queue,根据queue中取出的对象去将对应的JVM外面的内存进行操作。

 

 示范代码:

 1 /**
 2  * 虚引用 get不到,随时被回收的对象
 3  * 
 4  * 作用:管理堆外内存NIO
 5  * @author Lys
 6  *
 7  */
 8 
 9 import java.lang.ref.PhantomReference;
10 import java.lang.ref.Reference;
11 import java.lang.ref.ReferenceQueue;
12 import java.util.LinkedList;
13 import java.util.List;
14 
15 public class T04_phantomReference {
16 private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>();
17     public static void main(String[] args) {
18         PhantomReference<M> phantomReference = new PhantomReference<M>(new M(),QUEUE );
19         
20         new Thread(()->{
21             
22                 try {
23                     System.gc();
24                     Thread.sleep(1000);
25                 } catch (Exception e) {
26                     e.printStackTrace();
27                     Thread.currentThread().interrupt();
28                 }
29                 System.out.println(phantomReference.get());
30                 System.gc();
31             
32         }).start();
33         
34         new Thread(()->{
35             while (true) {
36                 Reference<? extends M> poll = QUEUE.poll();
37                 if (poll!=null) {
38                     
39                     System.out.println("----- 虚引用对象被jvm回收-------"+poll);
40                 }
41             }
42         }).start();
43     }
44 }

执行结果:

finalize
null
----- 虚引用对象被jvm回收-------java.lang.ref.PhantomReference@4a140fe5

 

posted on 2020-08-18 20:53  精品唯居  阅读(307)  评论(0编辑  收藏  举报