ToB企服应用市场:ToB评测及商务社交产业平台

标题: Java 四种引用类型(强引用、软引用、弱引用、虚引用) [打印本页]

作者: 涛声依旧在    时间: 2023-12-21 17:08
标题: Java 四种引用类型(强引用、软引用、弱引用、虚引用)
概述

Java 中的引用类似 C 语言中的指针,指向一个对象,比如:
  1. // person 就是指向 Person 实例“张三”的引用
  2. Person person = new Person("张三");
复制代码
在 JDK1.2 以前,Java 里的引用是很传统的定义:如果 reference 类型的数据中存储的数值代表的是另外一块内存的起始地址,就称该 reference 数据是代表某块内存、某个对象的引用
这种定义当然没有什么不对,但现在看来显得太狭隘了,比如我们希望描述一类对象:当内存空间足够时,能保留在内存中,如果内存空间在进行了垃圾收集后仍然紧张,则可以抛弃这些对象,很多系统的缓存功能都符合这样的应用场景
JDK1.2 对引用的概念作了补充,将引用分为强引用(Strongly Reference)、软引用(SoftReference)、弱引用(Weak Reference)和虚引用(Phantom Reference),强度依次减弱

强引用

Java 中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用。类似 Object obj = new Object()
当一个对象被强引用变量引用时,除非超过了引用的作用域或者显示地将相应强引用赋值为 null,否则是不可能被垃圾回收器回收的

软引用

软引用用来描述一些有用但非必须的对象,此类对象只有在进行一次垃圾收集仍然没有足够内存时,才会在第二次垃圾收集时被回收,需要用 java.lang.ref.SoftReference 类来实现
  1. public class SoftRefenenceDemo {
  2.     public static void main(String[] args) {
  3.         softRefMemoryEnough();
  4.         System.out.println("------------");
  5.         softRefMemoryNotEnough();
  6.     }
  7.     private static void softRefMemoryEnough() {
  8.         Object o1 = new Object();
  9.         SoftReference<Object> s1 = new SoftReference<Object>(o1);
  10.         System.out.println(o1);  // java.lang.Object@2503dbd3
  11.         System.out.println(s1.get());  // java.lang.Object@2503dbd3
  12.         o1 = null;
  13.         System.gc();
  14.         System.out.println(o1);  // null
  15.         System.out.println(s1.get());  // java.lang.Object@2503dbd3
  16.     }
  17.      /**
  18.       * JVM配置 -Xms5m -Xmx5m ,故意 new 一个大对象,使内存不足产生 OOM,看软引用回收情况
  19.       */
  20.     private static void softRefMemoryNotEnough() {
  21.         Object o1 = new Object();
  22.         SoftReference<Object> s1 = new SoftReference<Object>(o1);
  23.         System.out.println(o1);  // java.lang.Object@4b67cf4d
  24.         System.out.println(s1.get());  // java.lang.Object@4b67cf4d
  25.         o1 = null;
  26.         
  27.         try {
  28.           byte[] bytes = new byte[10 * 1024 * 1024];
  29.         } catch(Error e) {
  30.           e.printStackTrace();
  31.         }
  32.         
  33.         System.out.println(o1);  // null
  34.         System.out.println(s1.get());  // null
  35.     }
  36. }
复制代码
弱引用

弱引用用来描述那些非必须对象,但它的强度比软引用更弱一些。被软引用关联的对象只能生存到下一次垃圾收集发生为止,当垃圾收集器开始工作,无论当前内存是否足够,都会回收掉只被弱引用关联的对象,需要用 java.lang.ref.WeakReference 类来实现
  1. public class WeakReferenceDemo {
  2.     public static void main(String[] args) {
  3.         Object o1 = new Object();
  4.         WeakReference<Object> w1 = new WeakReference<Object>(o1);
  5.         System.out.println(o1);  // java.lang.Object@7440e464
  6.         System.out.println(w1.get());  // java.lang.ref.WeakReference@49476842
  7.         o1 = null;
  8.         System.gc();
  9.         System.out.println(o1);  // null
  10.         System.out.println(w1.get());  // null
  11.     }
  12. }
复制代码
虚引用

虚引用,顾名思义,就是形同虚设,与其他几种引用都不太一样,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用必须和引用队列(RefenenceQueue)联合使用。虚引用的主要作用是跟踪对象垃圾回收的状态,仅仅是提供了一种确保对象被 finalize 以后,收到一个系统通知或者后续添加进一步的处理
  1. public class PhantomReferenceDemo {
  2.     public static void main(String[] args) throws InterruptedException {
  3.         Object o1 = new Object();
  4.         ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
  5.         PhantomReference<Object> phantomReference = new PhantomReference<Object>(o1,referenceQueue);
  6.         System.out.println(o1);  // java.lang.Object@7440e464
  7.         System.out.println(referenceQueue.poll());  // null
  8.         System.out.println(phantomReference.get());  // null
  9.         o1 = null;
  10.         System.gc();
  11.         Thread.sleep(3000);
  12.         System.out.println(o1);  // null
  13.         System.out.println(referenceQueue.poll()); // java.lang.ref.PhantomReference@49476842
  14.         System.out.println(phantomReference.get());  // null
  15.     }
  16. }
复制代码
ReferenceQueue 是用来配合引用工作的,没有ReferenceQueue 一样可以运行。SoftReference、WeakReference、PhantomReference 都有一个可以传递 ReferenceQueue 的构造器。创建引用的时候,可以指定关联的队列,当 GC 释放对象内存的时候,会将引用加入到引用队列。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动,这相当于是一种通知机制。当关联的引用队列中有数据的时候,意味着指向的堆内存中的对象被回收。通过这种方式,JVM 允许我们在对象被销毁后,做一些我们自己想做的事情

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4