ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

强引用、软引用、弱引用、虚引用的区别及使用场景

强引用、软引用、弱引用、虚引用的区别及使用场景 JVM 回收时强引用、软引用、弱引用、虚引用的区别及使用场景Java为什么要设计这四种引用Java的内存分配和内存回收由JVM去负责而无须程序员负责一个对象是否可以被回收主要看是否有引用指向此对象叫可达性分析。主要有两种方法引用计数法因存在循环引用故不常用可达性分析法Java设计这四种引用的主要目的有两个可以让程序员通过代码的方式来决定某个对象的生命周期。有利用垃圾回收提高垃圾回收效率。Java中的四种引用类型的对比引用类型特性使用场景强引用只要某个对象有强引用与之关联该对象永远不会被回收即使内存不足JVM宁愿抛出OOM也不会去回收。99%的开发场景都是强引用软引用发生GC后内存还是不足会回收缓存当内存足够可以正常的拿到缓存当内存不够就会先干掉缓存不至于马上抛出OOM。弱引用发生GC后就会回收ThreadLocal、WeakHashMap虚引用创建后立马会回收并且会把回收的通知放到ReferenceQueue中。无法通过虚引用来获取对一个对象的真实引用。在NIO中就运用了虚引用管理堆外内存。还可用来跟踪对象被垃圾回收器回收的活动当一个虚引用关联的对象被垃圾收集器回收之前会收到一条系统通知。强引用代码实现Object obj new Object(); Obj null;对于一个普通的对象如果没有其他的引用关系只要超过了引用的作用域或者显式地将相应强引用赋值为 null就是可以被垃圾收集的了具体回收时机还是要看垃圾收集策略。软引用有当 JVM 认为内存不足时才会去试图回收软引用指向的对象即 JVM 会确保在抛出 OutOfMemoryError 之前清理软引用指向的对象。软引用可以和一个引用队列ReferenceQueue联合使用如果软引用所引用的对象被垃圾回收器回收Java虚拟机就会把这个软引用加入到与之关联的引用队列中。后续我们可以调用ReferenceQueue的poll()方法来检查是否有它所关心的对象被回收。如果队列为空将返回一个null否则该方法返回队列中前面的一个Reference对象。代码实现设置 JVM 参数为 -Xms5m -Xmx5m -XX:PrintGCDetails/** * author Evan Walker * version 1.0 * 昂焱数据 https://www.ayshuju.com/ * desc 软引用 * date 2023/03/13 14:47:12 */ public class SoftReferenceDemo { public static void main(String[] args) { Object obj new Object(); SoftReferenceObject softReference new SoftReference(obj); obj null; try { // 分配 5 M ,因为堆内存5M小于创建对象10M故会进行垃圾回收 byte[] bytes new byte[10 * 1024 * 1024]; } catch (Exception e) { e.printStackTrace(); } finally { System.out.println(软引用 softReference.get()); } } }发现当内存不够时虚引用会被回收。PS对照实验不配子jvm参数可正常打印对象。弱引用在垃圾回收器线程扫描它所管辖的内存区域的过程中一旦发现了具有弱引用的对象不管当前内存空间足够与否都会回收它的内存。由于垃圾回收器是一个优先级很低的线程因此不一定会很快回收弱引用的对象。弱引用可以和一个引用队列ReferenceQueue联合使用如果弱引用所引用的对象被垃圾回收Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。/** * author Evan Walker * version 1.0 * 昂焱数据 https://www.ayshuju.com/ * desc 弱引用 * date 2023/03/13 14:47:12 */ public class ReferenceQueueDemo { public static void main(String[] args) throws InterruptedException { Object obj new Object(); WeakReferenceObject weakReference new WeakReference(obj); System.out.println(obj); System.out.println(weakReference.get()); obj null; System.gc(); System.out.println(GC之后....); System.out.println(obj); System.out.println(weakReference.get()); // System.out.println(------------我是和谐分割线----------); Object obj1 new Object(); ReferenceQueueObject referenceQueue1 new ReferenceQueue(); WeakReferenceObject weakReference1 new WeakReference(obj1, referenceQueue1); System.out.println(obj1); System.out.println(weakReference1.get()); System.out.println(weakReference1); obj1 null; System.gc(); Thread.sleep(500); System.out.println(GC之后....); System.out.println(obj1); System.out.println(weakReference1.get()); System.out.println(weakReference1); } }虚引用虚引用也叫幻象引用通过PhantomReference类来实现无法通过虚引用访问对象的任何属性或函数。仅仅是提供了一种确保对象被 finalize 以后做某些事情的机制。如果一个对象仅持有虚引用那么它就和没有任何引用一样在任何时候都可能被垃圾回收器回收。虚引用必须和引用队列 ReferenceQueue联合使用。当垃圾回收器准备回收一个对象时如果发现它还有虚引用就会在回收对象的内存之前把这个虚引用加入到与之关联的引用队列中。eferenceQueue queue new ReferenceQueue (); PhantomReference pr new PhantomReference (object, queue);
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进