• 【面试】JAVA四种引用 -强引用、软引用、弱引用、虚引用


    目录

    概述

    强引用

    软引用

    典型使用场景

    弱引用

    典型使用场景

    虚引用

     典型使用场景

    场景验证

    Cleaner

    示例代码

    输出结果


    概述

            Java中的引用关系可以分为强引用,软引用(SoftReference)、弱引用(WeakReference)和虚引用(PhantomReference);引用与对象以及GC Root直接的关系如下图所示:

    强引用

         强引用就是普通的赋值语句,只要GC Root到对象之间存在引用关系,改对象就不会被回收

    软引用

            软引用要弱于强引用,在GC Root 到引用对象之间还存在可达关系,只要JVM认为存在OOM风险就可以被回收

    典型使用场景

            1.缓存,被回收不影响系统可用性;比如在JDK反射中使用较多

    弱引用

            弱引用关系要比软引用之间的关系更弱,只要发生GC就会被回收,不管内存空间是否充足;也可以配合引用队列使用

    典型使用场景

            1.缓存,比如WeakHashMap, ThreadLocal等

    虚引用

            虚引用是最特殊的一个引用,虚引用的简单来讲就是形同虚设,无法从引用中获取引用对象,既然这样,虚引用的作用是什么呢?它主要用来跟踪对象被垃圾回收的活动,当垃圾
    回收器准备回收这个对象时,如果发现它有虚引用就会将这个虚引用添加到与之关联的引用队列中。

     典型使用场景

          对象回收时,清理关联资源,比如Cleaner,以及堆外缓存管理等。

    场景验证

    为了验证是引用关系是否如上文所述,特准备如下代码:

    1. public class 四种引用 {
    2. public static void main(String[] args) throws InterruptedException {
    3. //强引用
    4. Object strongReference = new Object();
    5. //引用队列
    6. ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
    7. /**
    8. * 软引用
    9. * 如果仅有软引用对象时,首次垃圾回收不会回收改对象,再次回收时才会回收改对象
    10. * 软引用可以配合引用队列使用
    11. */
    12. SoftReference<Object> softReference = new SoftReference<>(new Object(), referenceQueue);
    13. //reference handler
    14. new Thread(() -> {
    15. try {
    16. Reference<? extends Object> reference = null;
    17. while ((reference = referenceQueue.remove()) != null) {
    18. if (reference instanceof SoftReference) {
    19. System.out.println("软引用引用对象被回收");
    20. }
    21. if (reference instanceof PhantomReference) {
    22. System.out.println("虚引用引用对象被回收");
    23. }
    24. if (reference instanceof WeakReference) {
    25. System.out.println("弱引用引用对象被回收");
    26. }
    27. }
    28. } catch (InterruptedException e) {
    29. throw new RuntimeException(e);
    30. }
    31. }).start();
    32. /**
    33. * 如果仅有弱引用,只要发生垃圾回收就会回收改对象
    34. */
    35. WeakReference<Object> weakReference = new WeakReference<>(new Object(), referenceQueue);
    36. System.out.println("弱引用:" + weakReference.get());
    37. //手动执行GC,
    38. System.gc();
    39. // 手动执行GC 后 弱引用被引用的对象已经被回收了,此时get到的值为null
    40. System.out.println("弱引用:" + weakReference.get());
    41. /**
    42. * 必须配合引用队列使用,当虚引用引用的对象回收时,会将徐引用对象入队,由Referen Handler线程释放其关联的外部资源
    43. */
    44. PhantomReference<Object> phantomReference = new PhantomReference<>(new Object(), referenceQueue);
    45. try {
    46. SoftReference<HashMap> holder = new SoftReference<>(new HashMap<>());
    47. for (int i = 0; i < 1000; i++) {
    48. HashMap hashMap = holder.get();
    49. Thread.sleep(20);
    50. if (Objects.nonNull(hashMap)) {
    51. hashMap.put(i, new Object[1024]);
    52. }
    53. if (softReference.get() == null) {
    54. System.out.println("强引用: " + strongReference);
    55. System.out.println("软引用:" + softReference.get());
    56. break;
    57. }
    58. }
    59. } catch (Throwable e) {
    60. System.out.println("OutOfMemoryError后:" + softReference.get());
    61. }
    62. System.out.println("强引用: " + strongReference);
    63. System.out.println("软引用:" + softReference.get());
    64. System.out.println("弱引用:" + weakReference.get());
    65. System.out.println("虚引用 " + phantomReference.get());
    66. TimeUnit.SECONDS.sleep(20);
    67. System.exit(-1);
    68. }
    69. }

    jvm 参数:-Xms3m -Xmx3m 执行结果如下:

    1. 弱引用:java.lang.Object@5ca881b5
    2. [0.087s][info ][gc,start ] GC(1) Pause Full (System.gc())
    3. 弱引用引用对象被回收
    4. 弱引用:null
    5. [1.193s][info ][gc,ergo ] Attempting maximum full compaction clearing soft references
    6. 软引用引用对象被回收
    7. 虚引用引用对象被回收
    8. 强引用: java.lang.Object@24d46ca6
    9. 软引用:null
    10. 强引用: java.lang.Object@24d46ca6
    11. 软引用:null
    12. 弱引用:null
    13. 虚引用 null

    Cleaner

             在程序执行过程中创建的对象将由垃圾收集器 (GC)自动删除。当某个对象未被任何线程引用时,并且当JVM确定无法访问该对象时,则可以进行垃圾回收。
     Object类具有finalize() 方法,在尝试从堆中删除对象之前,GC 将自动调用该方法。在Java 9中,已经不建议使用finalize()方法,并将新类java.lang.ref.Cleaner 添加到垃圾回收管理中。当对象可以进行垃圾回收时,Cleaner 类的对象会自动得到通知。需要通过使用register()方法向清理器对象注册正在垃圾回收的对象

    示例代码

    1. public class CleanerTest {
    2. public static void test() {
    3. Object instance = new Object();
    4. Cleaner cleaner = Cleaner.create();
    5. cleaner.register(instance, () -> {
    6. System.out.println("do cleaner");
    7. });
    8. }
    9. public static void main(String[] args) {
    10. System.out.println("Cleaner Test");
    11. test();
    12. System.gc();
    13. }
    14. }

    输出结果

    Cleaner Test
    do cleaner

  • 相关阅读:
    FastDFS基础学习(二)之安装FastDFS
    python编程复习系列——week3决策声明(if-else)
    mybatics 连接池-Druid
    Docker学习笔记
    软考机考 画图
    咖啡赛道1个月6起新融资,该不该投?投融资另类数据深度解析
    快速开发项目-VScode插件
    Axure RP PC电商平台Web端交互原型模板
    Java集合-Map接口
    宣泰医药通过注册:拟募资6亿 联和投资是大股东
  • 原文地址:https://blog.csdn.net/zhangwei_david/article/details/125433173