强软弱虚四大引用 2024-04-18 16:04 ### 强引用 程序中95%以上都是强引用: ```java Student s = new Student(); ``` 这就是强引用,s引用堆空间的一块内存区域。 强引用是程序中使用的对象,即使内存不足时,发生了GC也不能清理他。因为一旦清理了强引用对象则程序有可能就执行不下去了。 当手动赋空: ```java s = null; ``` 这时,若没有其他引用指向new的这块空间,则这块内存区域在发生GC时有可能被回收。 ### 软引用 特殊情况下用到: ```java SoftReference<User> softReference = new SoftReference<>(new User(1, "xxx")); ``` 这是软引用,需要使用特定的对象`SoftReference`包住。 上面一行代码等于下面三行: ```java User u1 = new User(1, "xxx"); SoftReference<User> softReference = new SoftReference<>(u1); u1 = null; ``` 当发生GC时,若内存充足,则不会回收软引用对象。若内存不足,则有可能回收软引用对象。 > 前提是软引用对象包住的实例没有被其他强引用指向。上述三行代码中 u1 刚开始指向了这个对象,后来赋空了,这样user这个实例就变成了一个只有软引用指向的对象了。 #### 演示软引用内存不足时被回收 ```java import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.lang.ref.SoftReference; /** * 将堆内存设置为10M 并打印GC详细信息 * -Xms10m -Xmx10m -XX:+PrintGCDetails */ public class SoftReferenceTest { @Data @NoArgsConstructor @AllArgsConstructor public static class User { private int id; private String name; } public static void main(String[] args) { SoftReference<User> softReference = new SoftReference<>(new User(1, "xxx")); //获取对象 System.out.println(softReference.get()); //建议JVM执行full gc System.gc(); System.out.println("After GC"); System.out.println(softReference.get()); try { //估计让堆内存放不下,JVM自动触发full gc byte[] bytes = new byte[7168 * 1024]; } catch (Throwable e) { e.printStackTrace(); } finally { System.out.println("Second GC"); System.out.println(softReference.get()); } } } /* SoftReferenceTest.User(id=1, name=xxx) After GC SoftReferenceTest.User(id=1, name=xxx) Second GC null 说明软引用在内存不足时GC会进行回收 */ ``` #### 应用 缓存 ### 弱引用 特殊情况下用到: ```java WeakReference<User> weakReference = new WeakReference<>(new User(1, "xxx")); ``` 这是弱引用,需要使用WeakReference包住。 只要发生了GC,无论内存充足与否,都会回收弱引用对象。 #### 演示弱引用发现即回收 ```java import java.lang.ref.WeakReference; import com.example.strategydemo.test.refence.SoftReferenceTest.User; /** * 弱引用只要发生GC即回收,不用调整堆大小 */ public class WeakReferenceTest { public static void main(String[] args) { WeakReference<User> weakReference = new WeakReference<>(new User(1, "xxx")); System.out.println(weakReference.get()); System.gc(); System.out.println("After GC"); System.out.println(weakReference.get()); } } /* SoftReferenceTest.User(id=1, name=xxx) After GC null */ ``` #### 应用 可有可无的缓存数据 ### 虚引用 > 基本不用 PhantomReference,也叫幽灵引用或幻影引用,是所有引用中最弱的一个。不能单独使用,也无法get()到。如果一个对象仅持有虚引用,那么他跟没有引用是一样的,随时会被垃圾回收。 唯一的目的就是跟踪垃圾回收过程:在这个对象被回收时发出一个系统通知,让系统知道这个对象被回收掉了。 #### 演示虚引用 ```java package com.example.strategydemo.test.refence; import java.lang.ref.PhantomReference; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; public class PhantomReferenceTest { public static void main(String[] args) { // 创建一个对象 Object obj = new Object(); // 创建一个引用队列 ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>(); // 创建一个虚引用,并将其与对象和引用队列关联起来 PhantomReference<Object> phantomReference = new PhantomReference<>(obj, referenceQueue); // 不再持有强引用 obj = null; // 从虚引用获取对象 // 虚引用不会影响对象的生命周期,因此此时从虚引用中获取的对象总是返回 null System.out.println("从虚引用获取的对象:" + phantomReference.get()); // 输出 null System.gc(); // 等待一段时间,以便观察垃圾回收的效果 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 从引用队列中获取引用 Reference<?> polledReference = referenceQueue.poll(); if (polledReference != null) { System.out.println("从引用队列中获取的引用:" + polledReference); } else { System.out.println("引用队列中没有引用被放入"); } } } /* 从虚引用获取的对象:null 从引用队列中获取的引用:java.lang.ref.PhantomReference@8efb846 */ ``` 从虚引用中获取不到对象,因为虚引用不会影响对象的生命周期。 虚引用总是和一个引用队列关联(上述ReferenceQueue),当虚引用所引用的对象被垃圾回收时,JVM会将虚引用添加到这个队列中。 它的作用主要在于垃圾回收发生时的通知和清理操作、以及一些特殊的资源释放,而不是作为对象的引用使用。 #### 应用 资源释放的操作放在虚引用中。 ### 终结器引用 用以实现对象的finalize()方法 ### 总结 ##### 强引用:不回收 ##### 软引用:内存不足即回收 ##### 弱引用:发现即回收 ##### 虚引用:对象回收跟踪 --END--
发表评论