• 每天一个面试题:四种引用,弱引用防止内存泄漏


    开始全新的学习,沉淀才会有产出,一步一脚印!
    面试题系列搞起来,这个专栏并非单纯的八股文,我会在技术底层的基础上,不至于Debug,还会做一些实例的实现,实现一些简单的Demo,或者用于我做过的项目中去;
    代码会同步在我的gitee中去,觉得不错的同学记得一键三连求关注,感谢:
    链接: Reference

    四种引用基本介绍

    • 强引用就是正常的new实例,这种关系是单独一对一的,由GCroot的引用链确定,不会被GC自动回收,需要手动收回;

    在这里插入图片描述

    • 软引用,是基于SoftReference确定的,类似于代理加工实现,首次gc不回收,内存不足回收
      软参考对象,由垃圾自行决定清除收集器响应内存需求。 软引用最常被用来实现内存敏感型缓存 public class SoftReference extends Reference {

    • 弱引用:只要gc就删除
      在这里插入图片描述

    • 虚引用:配合了一个队列进行使用,gc去将虚引用的对象及其外部资源回收掉
      在这里插入图片描述

    实例Demo

    - 虚引用

    
    public class TestPhantomfegerence {
    
    
    
        static class MyResource extends PhantomReference<String>{
    
    	//继承了虚引用类,构造方法中对应了 构造的 对象和队列
            public MyResource(String referent, ReferenceQueue<? super String> q) {
                super(referent, q);
            }
    
            public void  clean(){
                System.out.println("clean");
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    进行测试

        public static void main(String[] args) {
            ReferenceQueue<String> queue = new ReferenceQueue<>();
            List<MyResource> list = new ArrayList<>();
            list.add(new MyResource(new String("a"), queue));
            list.add(new MyResource("b", queue));
            list.add(new MyResource(new String("c"), queue));
    		
    		//调用系统GC
            System.gc();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Object obj;
    //       gc后,如果存在资源,就打印,可以看到new的对象被打印了
            while((obj = queue.poll())!=null){
                if(obj instanceof MyResource ){
                    ((MyResource) obj).clean();
                }
            }
    
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    弱引用防止内存泄漏

    ThreadLocalMap中存在内存泄漏问题,这里可以通过一下这种方式实现

    
    public class TestWeakReference {
    
        public static void main(String[] args) {
            MyweakMap map = new MyweakMap(5);
            map.put(0, new String("a"), "1");
            map.put(1, ("b"), "2");
            map.put(2, ("c"), "3");
            map.put(3, new String("d"), "3");
            System.out.println(map);
            System.gc();
            System.out.println(map.get("a"));
            System.out.println(map.get("b"));
            System.out.println(map.get("c"));
            System.out.println(map.get("d"));
            map.clean();
            System.out.println(map);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
        static class MyweakMap{
            static ReferenceQueue<Object> queue = new ReferenceQueue<>();
            static class Entry extends WeakReference<String> {
                String value;
    			//这里的value设定,让key成为了一个弱引用,value成强引用
                public Entry(String key, String value) {
                    super(key,queue);
                    this.value = value;
                }
    
                @Override
                public String toString() {
                    return "Entry{" +
                            "value='" + value + '\'' +
                            '}';
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    这里是通过判断当前的key是否为null来进行的

            public void clean(){
                Object object;
                while((object=queue.poll())!=null){
                    for (int i = 0; i < table.length; i++) {
                        if(table[i]==object){
                            table[i]=null;
                        }
                    }
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    如果为null,就将当前table,也就是对象Entry[]对应的单个Entry直接设置为null, static class Entry extends WeakReference { 这就断开了联系
    在这里插入图片描述

            public MyweakMap(int init){
                table= new Entry[init];
            }
            Entry[] table;
    
            public void put(int index, String key, String value){
                table[index] = new Entry(key, value);
            }
    
            public String get(String key){
                for(Entry entry : table){
                    if(entry!=null){
                        String k = entry.get();
                        if(k!=null&&k.equals(key)){
                            return entry.value;
                        }
                    }
                }
                return null;
            }
    
    
            @Override
            public String toString() {
                return "MyweakMap{" +
                        "table=" + Arrays.toString(table) +
                        '}';
            }
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述

    弱引用

    public class TestSoft {
    
        static class WeakReferenceDemo extends WeakReference<String> {
            public WeakReferenceDemo(String referent) {
                super(referent);
                System.out.println(referent);
            }
    
    
        }
    
    
    
        public static void main(String[] args) {
    
            List<WeakReference> list = new ArrayList<>();
            list.add(new TestSoft.WeakReferenceDemo(new String("a")));
            list.add(new TestSoft.WeakReferenceDemo(("b")));
            list.add(new TestSoft.WeakReferenceDemo(new String("c")));
    
    
            System.out.println(list.get(0).get());
    
            System.gc();
    
            System.out.println(list.get(0).get());
    
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    结果展示 a b c a null

    Debug分析源码

    引用的底层很简单

    public class WeakReference<T> extends Reference<T> {
    
        public WeakReference(T referent) {
            super(referent);
        }
    
        public WeakReference(T referent, ReferenceQueue<? super T> q) {
            super(referent, q);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    一个泛型类

    public abstract class Reference<T> {
    
     
        private T referent;         /* Treated specially by GC */
    
        volatile ReferenceQueue<? super T> queue;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    链表结构

        @SuppressWarnings("rawtypes")
        Reference next;
    
    
        transient private Reference<T> discovered;  /* used by VM */
    
    
    
        static private class Lock { };
        private static Lock lock = new Lock();
    
    
    
        private static Reference<Object> pending = null;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    实现了一个静态内部类ReferenceHandler

      private static Lock lock = new Lock();
    
    • 1

    加载一个类锁

        private static class ReferenceHandler extends Thread {
    
            ReferenceHandler(ThreadGroup g, String name) {
                super(g, name);
            }
    
            public void run() {
                for (;;) {
                    Reference<Object> r;
                    synchronized (lock) {
                        if (pending != null) {
                            r = pending;
                            pending = r.discovered;
                            r.discovered = null;
                        } else {
    
                            try {
                                try {
                                    lock.wait();
                                } catch (OutOfMemoryError x) { }
                            } catch (InterruptedException x) { }
                            continue;
                        }
                    }
    
                    // Fast path for cleaners
                    if (r instanceof Cleaner) {
                        ((Cleaner)r).clean();
                        continue;
                    }
    
                    ReferenceQueue<Object> q = r.queue;
                    if (q != ReferenceQueue.NULL) q.enqueue(r);
                }
            }
        }
    
        static {
            ThreadGroup tg = Thread.currentThread().getThreadGroup();
            for (ThreadGroup tgn = tg;
                 tgn != null;
                 tg = tgn, tgn = tg.getParent());
            Thread handler = new ReferenceHandler(tg, "Reference Handler");
            /* If there were a special system-only priority greater than
             * MAX_PRIORITY, it would be used here
             */
            handler.setPriority(Thread.MAX_PRIORITY);
            handler.setDaemon(true);
            handler.start();
        }
    
    
        public T get() {
            return this.referent;
        }
    
    
        public void clear() {
            this.referent = null;
        }
    
    
        public boolean enqueue() {
            return this.queue.enqueue(this);
        }
    
    
        /* -- Constructors -- */
    
        Reference(T referent) {
            this(referent, null);
        }
    
        Reference(T referent, ReferenceQueue<? super T> queue) {
            this.referent = referent;
            this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
  • 相关阅读:
    01-SpringSecurity认证流程
    将 TiDB 迁移至 Kubernetes
    数据分析之pandas(进阶)
    [C国演义] 第十六章
    【Leetcode】377. 组合总和 Ⅳ
    esp-idf 移植 lvgl8.3.3
    Ocelot的限流、熔断和负载均衡
    信息隐藏与探索 中职网络安全
    Git使用总结
    掌握CSS Flexbox,打造完美响应式布局,适配各种设备!
  • 原文地址:https://blog.csdn.net/futurn_hero/article/details/128212326