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

news2024/9/22 10:03:03

每天一个面试题:四种引用

  • 四种引用基本介绍
  • 实例Demo
    • - 虚引用
    • 弱引用防止内存泄漏
    • 弱引用
  • Debug分析源码

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

四种引用基本介绍

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

在这里插入图片描述

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

  • 弱引用:只要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");
        }
    }

进行测试

    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();
            }
        }


    }

}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

弱引用防止内存泄漏

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);
    }

    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 + '\'' +
                        '}';
            }
        }

这里是通过判断当前的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;
                    }
                }
            }
        }

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

        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) +
                    '}';
        }
    }

}

在这里插入图片描述

弱引用

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());


    }
}

结果展示 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);
    }

}

一个泛型类

public abstract class Reference<T> {

 
    private T referent;         /* Treated specially by GC */

    volatile ReferenceQueue<? super T> queue;

链表结构

    @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;

实现了一个静态内部类ReferenceHandler

  private static Lock lock = new Lock();

加载一个类锁

    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;
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/67889.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

配对交易之统计套利配对:协整(cointegration)

Engle和Granger观察到了一个相当有趣的现象。尽管两个时间序列是非平稳的&#xff0c;但在某些情况下&#xff0c;两者的特定线性组合实际上是平稳的&#xff1b;也就是说&#xff0c;这两个序列在某种程度上是步调一致的。Engle和Granger创造了“协整”&#xff08;cointegrat…

【Tensorflow+自然语言处理+LSTM】搭建智能聊天客服机器人实战(附源码、数据集和演示 超详细)

需要源码和数据集请点赞关注收藏后评论区留言私信~~~ 一、自然语言处理与智能 自然语言处理技术是智能客服应用的基础&#xff0c;在自然语言处理过程中&#xff0c;首先需要进行分词处理&#xff0c;这个过程通常基于统计学理论&#xff0c;分词的精细化可以提升智能客服的语…

小白课程,前端入门新手,必须了解的回调函数概念和应用实例

******内容预警******新手内容&#xff0c;大佬请绕道 做为一个纯纯的小白&#xff0c;我相信很多人是没有回掉函数这个概念的&#xff0c;虽然很多文档和教程中都有提到&#xff0c;但是很多人看完文档也不会用。因为菜鸟的开发任务&#xff0c;都是简单画一下html页面&#x…

分布式定时调度:xxl-job 最佳实践详解

文章目录一、定时任务概述1.1. 什么是定时任务1.2. 常见定时任务方案1.3. 分布式定时任务面临的问题1.4. 分布式定时任务xxl-job二、xxl-job架构设计2.1. 设计思想2.2. 架构设计图三、xxl-job安装3.1.下载源码3.2. 导入数据库3.3. 启动调度中心3.4. 配置部署“执行器项目3.5. 案…

护眼灯有用吗?双十二买什么样的护眼灯真的有效果

对于很多人来说&#xff0c;健康是一个越来越重视的话题&#xff0c;特别是现代社会生活节奏很快&#xff0c;很多人的眼睛都吃不消&#xff0c;所以不管是为了好看&#xff0c;还是为了能够看得足够远&#xff0c;都会注意保护眼睛&#xff0c;所以越来越多的人开始考虑护眼台…

网站变灰,6行代码,通通变灰

人狠话不多&#xff0c;直接上代码 -webkit-filter: grayscale(100%); -moz-filter: grayscale(100%); -ms-filter: grayscale(100%); -o-filter: grayscale(100%); filter: grayscale(100%); filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale1); 通通变灰&…

Java中Map集合体系的基本使用和常用API

文章目录Map集合体系Map集合概述和使用Map集合体系的特点Map集合常用的APIMap集合体系 Map集合概述和使用 Map集合是一种双列集合&#xff0c;每个元素包含两个数据。 Map集合的每个元素的格式&#xff1a;keyvalue(键值对元素)。 Map集合也被称为“键值对集合”。 Map集合整体…

本地代码上传到gitlab

1、在本地代码目录中&#xff0c;鼠标右键Git Bash Here&#xff0c;会打开一个git命令操作窗口&#xff1b; 2、执行git init命令&#xff0c;此命令会在当前目录下创建一个.git文件夹, git init 3、将项目的所有文件添加到仓库中&#xff0c; git add -A 4、将add的文件…

【计算机毕业设计】75.教师工作考核绩效管理系统源码

一、系统截图&#xff08;需要演示视频可以私聊&#xff09; 摘 要 随着社会不断进步与发展&#xff0c;生活节奏不断加快&#xff0c;信息已经成为我们生活中不可缺少的一部分&#xff0c;很多学校需要掌握大量的信息来了解特定学生的需求&#xff0c;传统的做法是组织大量的…

如何实现table表头固定但是tbody可以滚动【附源码实例】

【写在前面】经常看到表头固定&#xff0c;表身支持滚动的需求&#xff0c;由于项目经常会用到一些自定义的表格展示数据&#xff0c;之前经常发现每次都是自己去写&#xff0c;自己去重新定义样式&#xff0c;觉得特别的麻烦&#xff0c;现在我特针对这类的分享一下。 1、页面…

【电巢】新能源产业景气度加速向上,功率器件3000亿赛道国产替代已在路上!(附70+厂家名单部分厂家替代型号)

前言 目前消费电子疲软继续蔓延&#xff0c;半导体设计端分化明显&#xff0c;存储、CPU等产品需求延续弱势&#xff0c;但IGBT和SiC等功率器件逐步迎来收获期。半导体周期拐点已至&#xff0c;曙光乍现。 在整个半导体周期背景下&#xff0c;新能源汽车俨然已成为逆势窗口产业…

现在健身耳机哪个牌子好、2023年最好的健身房耳机推荐

很多朋友在运动健身的时候喜欢戴上耳机&#xff0c;在音乐的节奏中去运动&#xff0c;现在市面上的运动耳机选择也特别丰富&#xff0c;但是说实话&#xff0c;从专业角度来看能真正适合运动的蓝牙耳机其实还是比较罕见的。这也就导致了我们许多朋友在选购时特别容易踩坑&#…

React - redux 使用(由浅入深)

React - redux 使用&#xff08;由浅入深&#xff09;一. redux理解1. redux 介绍2. redux 使用情况3. redux 工作流程4. redux 三个核心概念4.1 Action4.2 Store4.3 Reducers5. redux 核心API5.1 createStore()5.2 Store5.2.1 Store 方法5.2.1.1 getState()5.2.1.2 dispatch(a…

Kotlin 开发Android app(十八):线程Thread和UI更新

多线程的好处是不言而喻的&#xff0c;它能帮我们刚更多的事情&#xff0c;同时干不同的事情在程序设计中是经常出现的&#xff0c;这种时候我们使用的是线程。 在Kotlin 中&#xff0c;使用的还是原先java 的那一套&#xff0c;用的还是Thread &#xff0c;可能是在java 中T…

翻译: 如何学习编译器:LLVM Edition

编译器和编程语言是一个很大的话题。您不能只选择学习路径并在某个时候完成它。有许多不同的区域&#xff0c;每个区域都是无穷无尽的。 在这里&#xff0c;我想分享一些有助于学习编译器的链接。这份清单不可能详尽无遗——每个人都很忙&#xff0c;没有人有时间阅读龙书。 …

前端知识大全之CSS

目录 一、概念讲解 学习CSS之前必学的HTML &#xff08;超链接&#xff09; 二、正文代码 1.行内样式 2.内部样式&#xff08;选择器&#xff09; 3.外部样式 4.样式的优先级 5.简单选择器之定义单个标签&#xff08;id&#xff09; 6.简单选择器之定义多个标签&#xff…

低代码平台,企业业务创新的最佳路径

数字化转型的必然趋势及面临的问题 数字经济时代&#xff0c;数字化转型是企业在行业赛道上领先的必经之路&#xff0c;然而&#xff0c;数字化转型升级的道路并不是畅通无阻的&#xff0c;也不是企业单枪匹马就能干成的&#xff0c;各个企业在转型过程中都或多或少会遇到技术…

MySQL-索引

一、介绍 索引是数据库对象之一&#xff0c;用于提高字段检索效率&#xff0c;使用者只需要对哪个表中哪些字段建立索引即可&#xff0c;其余什么都不做&#xff0c;数据库会自行处理。 索引提供指向存储在表的指定列中的数据值的指针&#xff0c;如同图书的目录&#xff0c;…

【MMDetection】MMDetection中AnchorGenerator学习笔记

文章目录初始化-AnchorGenerator()Anchor平移-grid_priors计算有效anchor-valid_flags参考文献初始化-AnchorGenerator() TASK_UTILS.register_module() class AnchorGenerator:def __init__(self, strides, ratios, scalesNone, base_sizesNone, scale_majorTrue, octave_bas…

numpy的部分通用函数浅谈

numpy的部分通用函数 1.数组算术运算符 运算符对应的通用函数描述np.add加法运算&#xff08;即112)-np.substract减法运算&#xff08;即3-21&#xff09;-np.negative负数运算&#xff08;即-2&#xff09;*Nnp.multiply乘法运算&#xff08;即2*36&#xff09;/np.divide除…