面试被问Java的四种引用却一脸懵逼?莫慌,今天一次性说清楚!

阿里面试题:强、软、弱、虚引用的特点及应用场景 前言很多小伙伴们都提到过去面试的时候,经常有面试官问到知道强引用、软引用、弱引用、虚引用吗?他们各自的特点是什么?很多老司机对这些也不是太了解,今天老顾就来介绍一下。垃圾回收我们都知道java的JVM有垃圾回收机制,GC判断堆中的对象实例或数据是不是垃圾的方法有引用计数法和可达性算法两种。无论是通过引用计数算法判断对象的引用数量,还是通过根搜索算法判断对象的引用链是否可达,判定对象是否存活都与“引用”有关,即是否要把这些对象视为垃圾回收掉引用我们先来说说什么是引用?Java中的引用,类似 C 语言中的指针。 阅读详情

前几天在CodeReview的时候,看到了一个用WeakHashMap的代码,进而聊到了WeakReference,再聊到Java四种引用类型。

回想了一下,上次学习Java的强软弱虚四种引用类型,还是在准备面试的时候。平时用得不多,一下子竟然想不清楚它们的区别,只记得它们的强度依次递减。

然后又看了一下这方面的文章,今天好好把它们理清楚。

四种引用的区别

其实四种引用的区别在于GC的时候,对它们的处理不同。用一句话来概括,就是:如果一个对象GC Root可达,强引用不会被回收,软引用在内存不足时会被回收,弱引用在这个对象第一次GC会被回收。

如果GC Root不可达,那不论什么引用,都会被回收

虚引用比较特殊,等于没有引用,不会影响对象的生命周期,但可以在对象被收集器回收时收到一个系统通知。

下面结合案例分别来讲一下四种引用在面对GC时的表现以及它们的常见用途。先设置一下JVM的参数:

-Xms20M -Xmx20M -Xmn10M -verbose:gc -XX:+PrintGCDetails

强引用

这就是我们平时最常使用的引用。只要GC的时候这个对象GC Root可达,它就不会被回收。如果JVM内存不够了,直接抛出OOM。比如下面这段代码就会抛出OutOfMemoryError:

public static void main(String[] args) {
    List<Object> list = new LinkedList<>();
    for (int i = 0; i < 21; i++) {
        list.add(new byte[1024 * 1024]);
    }
}

软引用

软引用,当GC的时候,如果GC Root可达,如果内存足够,就不会被回收;如果内存不够用,会被回收。将上面的例子改成软引用,就不会被OOM:

public static void main(String[] args) {
    List<Object> list = new LinkedList<>();
    for (int i = 0; i < 21; i++) {
        SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024]);
        list.add(softReference);
    }
}

我们把程序改造一下,打印出GC后的前后的差别:

public static void main(String[] args) {
    List<SoftReference<byte[]>> list = new LinkedList<>();
    for (int i = 0; i < 21; i++) {
        SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024]);
        list.add(softReference);
        System.out.println("gc前:" + softReference.get());
    }
    System.gc();
    for (SoftReference<byte[]> softReference : list) {
        System.out.println("gc后:" + softReference.get());
    }
}

会发现,打印出的日志,GC前都是有值的,而GC后,会有一些是null,代表它们已经被回收。

而我们设置的堆最大为20M,如果把循环次数改成15,就会发现打印出的日志,GC后没有为null的。但通过-verbose:gc -XX:+PrintGCDetails参数能发现,JVM还是进行了几次GC的,只是由于内存还够用,所以没有回收。

public static void main(String[] args) {
    List<SoftReference<byte[]>> list = new LinkedList<>();
    for (int i = 0; i < 15; i++) {
        SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024]);
        list.add(softReference);
        System.out.println("gc前:" + softReference.get());
    }
    System.gc();
    for (SoftReference<byte[]> softReference : list) {
        System.out.println("gc后:" + softReference.get());
    }
}

所以软引用的常见用途就呼之欲出了:缓存。尤其是那种希望这个缓存能够持续时间长一点的。

弱引用

软引用,只要这个对象发生GC,就会被回收。

把上面的代码改成软引用,会发现打印出的日志,GC后全部为null。

public static void main(String[] args) {
    List<WeakReference<byte[]>> list = new LinkedList<>();
    for (int i = 0; i < 15; i++) {
        WeakReference<byte[]> weakReference = new WeakReference<>(new byte[1024 * 1024]);
        list.add(weakReference);
        System.out.println("gc前:" + weakReference.get());
    }
    System.gc();
    for (WeakReference<byte[]> weakReference : list) {
        System.out.println("gc后:" + weakReference.get());
    }
}

所以弱引用也适合用来做缓存,不过由于它是只要发生GC就会被回收,所以存活的时间比软引用短得多,通常用于做一些非常临时的缓存。

我们知道,WeakHashMap内部是通过弱引用来管理entry的。它的键是“弱键”,所以在GC时,它对应的键值对也会从Map中删除。

Tomcat中有一个ConcurrentCache,用到了WeakHashMap,结合ConcurrentHashMap,实现了一个线程安全的缓存,感兴趣的同学可以研究一下源码,代码非常精简,加上所有注释,只有短短59行。

ThreadLocal中的静态内部类ThreadLocalMap里面的entry是一个WeakReference的继承类。

使用弱引用,使得ThreadLocalMap知道ThreadLocal对象是否已经失效,一旦该对象失效,也就是成为垃圾,那么它所操控的Map里的数据也就没有用处了,因为外界再也无法访问,进而决定擦除Map中相关的值对象,Entry对象的引用,来保证Map总是保持尽可能的小。

虚引用

虚引用的设计和上面三种引用有些不同,它并不影响GC,而是为了在对象被GC时,能够收到一个系统通知。

那它是怎么被通知的呢?虚引用必须要配合ReferenceQueue,当GC准备回收一个对象,如果发现它还有虚引用,就会在回收之前,把这个虚引用加入到与之关联的ReferenceQueue中。

那NIO是如何利用虚引用来管理内存的呢?

DirectBuffer直接从Java堆之外申请一块内存, 这块内存是不直接受JVM GC管理的, 也就是说在GC算法中并不会直接操作这块内存. 这块内存的GC是由于DirectBuffer在Java堆中的对象被GC后, 通过一个通知机制, 而将其清理掉的.

DirectBuffer内部有一个Cleaner。这个Cleaner是PhantomReference的子类。当DirectBuffer对象被回收之后, 就会通知到PhantomReference。然后由ReferenceHandler调用tryHandlePending()方法进行pending处理. 如果pending不为空, 说明DirectBuffer被回收了, 就可以调用Cleaner的clean()进行回收了。

上面这个方法的代码在Reference类里面,有兴趣的同学可以去看一下那个方法的源码。

去大厂面试被问懵了...Java面试官的多线程与锁追魂夺命10连问,80%的人都答不上来 趁着金三银四的季节,想着去大厂面试试一下,说不准咱遇到一个大冤种面试官成功上岸了呢。谁知道一上来面试官简历都没看,直接给我来了套并发多线程组合拳,直接把我给干懵了,大佬是我不配,打扰了。 回来后我把面试官的问题复盘了一下,现在就分享给大家,希望对大家面试有所帮助。当然,如果觉得博主总结的不错的话,希望能给个三连支持一下,让更多的人看到,谢谢啦。 1、什么是进程?什么是线程?(一个简单的暖场题) 进程是操作系统分配资源的最小单元 线程是操作系统调度的最小单元,线程隶属于进程。 一个程序至少有一个进程,一个. 阅读详情

相关推荐

单目标跟踪算法及其复现过程---SiamFC(一)

在test.py文件中,就是利用训练出来的模型进行测试,需要更改预训练模型的路径,测试集的路径,以OTB100为例,最后输出的是对每一帧目标位置的坐标点。代码如下:首先需要下载got10k官方库,只需要在终端输入(注意:在终端安装各种库的时候不能使用网络代理),在环境已经配置到的情况下,只需要该其中的路径和就可以运行。这个系列博客仅为了记录各目标跟踪算法的复现(大多为跑通大佬们实现的代码),包括其中出现的很多问题和错误,学到的新知识等等。解决,而且只使用在线的方法,限制了他们可以学习的模型的丰富性。

weixin_58244117的博客 4762

Java中的引用:强软弱虚

前言 之前在研究MVP的时候接触过弱引用,用来避免由于Activity被回收导致的内存泄露,但是当时只是浅尝辄止,没有系统的去接触引用这一块,没想到最近在看ThreadLocal的时候又看到关于引用的东西了,于是干脆就把这一块的东西都整理一下。正文1,引用是什么每种语言都有自己的数据处理方式,比如在c或c++中我们经常使用指针来间接的操纵对象,而在Java中,操纵的标识符实际上是指向一个对象的“句柄”

lypeer的专栏 5774

深入解析 ReDoc:从零构建高性能 API 文档的终极指南

ReDoc 是一个强大的开源工具,用于将 OpenAPI 规范转换为高质量、响应式的 API 文档。本文详细介绍了如何使用 ReDoc 构建和自定义 API 文档,包括如何编写支持 OpenAPI 的 API 注解、配置 HTML 页面以加载文档,以及如何利用 ReDoc 的高级功能进行定制。通过实例代码,您将学会如何灵活地展示 API 文档,提升用户体验。无论是初学者还是经验丰富的开发者,都能从本文中获得实用的技巧与方案,帮助快速搭建符合需求的 API 文档界面。

楠搏万的博客 4635

java四大引用

Java中的四大引用 强引用 最常用的,将一个对象赋值给引用变量,这个引用变量就是弱引用,gc不回收强引用的对象 软引用 softReference类实现 内存足,不回收,内存不足,回收。高速缓存 弱引用 WeakReference类实现 gc运行,直接回收 虚引用 PhantomReference类实现 不能单独使用,和引用队列联合使用 作用 跟踪对象被垃圾回收状态 ...

debug_fang的博客 236

电力市场小白必看:手把手教你用Matlab实现市场出清电价计算(附完整代码)

本文为电力市场初学者提供了使用Matlab计算市场出清电价的完整指南。通过Yalmip和Matpower工具包,详细讲解了从环境配置到模型构建、求解及结果分析的整个过程,帮助读者快速掌握节点电价计算的核心技术。

weixin_30379531的博客 74

CODESYS连接触摸屏

触摸屏:威纶通-MT8071iP(网络IP:192.168.1.10) 控制器:研华AMAX-5580(PAC)(Win10系统,网络IP:192.168.1.3) CODESYS RTE:RTE 64 V3.5 SP13 Build05 笔记本:Thinkpad L14(网络IP:192.168.1.2) CODESYS IDE:V3.5 SP13(ADD ON V3.5.13.5) 一、确认网络通讯正常(关闭防火墙) 笔记本与触摸屏网络测试情况 笔记本与控制器网络测试情况 二、控制器部分 1、新建

Leo的博客 1万+

JAVA第一周学习——一脸懵逼

面向对象: 面向对象乃是Java语言的核心,是程序设计的思想。Java语言的面向对象技术包括了面向对象和面向过程的基本概念,面向对象的特征,Java语言的类,对象,修饰符,抽象类等一系列的知识点 break语句:除了可以用于switch语句中,还可以用于循环体中 在循环体中遇见break语句时,立即结束循环,跳至循环外,执行循环结构后面的语句 continue语句:用于结束本次循环,即在循...

shadowlovey的博客 594

XGBoost调参新姿势:Bayesian优化实战指南(附完整代码)

本文详细介绍了如何使用Bayesian优化方法高效调优XGBoost模型参数。通过解析Bayesian优化核心原理和XGBoost关键参数,提供完整的实战代码示例,帮助读者掌握这一智能调参技术,显著提升模型性能。文章特别适合机器学习工程师和数据科学家阅读。

weixin_42536058的博客 366

面试官问我Redis怎么测,我一脸懵逼!

比如,针对请求参数变化不大,返回的数据跟db中存储的数据很接近的情况,适合在“里面”缓存数据,也就是在更新db的同时更新缓存,这种情况最优的状态下,只需要读缓存就够了,不需要跟db直接交互,能大大缓解db压力。这种场景一不需要使用缓存,二在商品信息被更新之后需要立即看到更新后的数据,不适合使用缓存,所以不建议使用缓存。且因业务数据庞大,各个统计sql执行效率非常低或无法直接统计:可以汇总各个指标,将统计值维护在缓存中,比如需要销量信息,每售出一件商品,销量统计值缓存+1,查看统计数据时查询此时的缓存即可。

kk_lzvvkpj的博客 1173

OpenSSH命令注入漏洞复现(CVE-2020-15778)

OpenSSH命令注入漏洞复现 1、简介 OpenSSH 是 SSH (Secure SHell) 协议的免费开源实现,ssh主要就是用来远程控制计算机,或传输文件,OpenSSH是使用SSH透过计算机网络加密通讯的实现。 2、漏洞概述 该漏洞是存在于scp在拷贝文件时产生的一个代码注入漏洞,攻击者可以利用此漏洞执行任意命令,比如:反弹shell, 3、影响版本 openssh <= openssh-8.3p1 4、实验环境 首先下载openssh,版本要符合漏洞影响的版本 服务端:apt-get

weixin_44537595的博客 3641

国密GmSSL v2版本命令行方式生成国密sm2私钥、公钥、签名和验证签名

GmSSL是国密算法的工具库(主要包含SM2、SM3、SM4和国密SSL证书生成等功能),项目本身是OpenSSL的分支,但是截至文章发布为止,OpenSSL主分支的国密算法并不完善,目前并不支持签名和解签,所以国密算法这块还是需要使用GmSSL工具库。网上现在并没有v2版本的GmSSL可用的命令行文章,本章用于记录这些命令。本文原创自csdn博客,其他网站看到这篇文章都是盗,版,爬。虫。网站,支持原创,远离盗版。

eguid音视频方向博客,分享经过实践检验的硬核音视频技术。FFmpeg、openCV和JavaCV音视频和图像处理系列教程发布十周年,众多开发者的严格验证。欢迎关注,一起交流探索学习最新音视频和图像处理技术 4606

国庆前阿里二面被Spring AOP三连问给问的一脸懵逼!

小编精心为大家准备了一手资料以上Java高级架构资料、源码、笔记、视频。Dubbo、Redis、设计模式、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术【附】架构书籍BAT面试的20道高频数据库问题解析Java面试宝典Netty实战算法BATJ面试要点及Java架构师进阶资料《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取![外链图片转存中…(img-cA84iB8r-1711931991176)]

2401_84009192的博客 919

抖音创作者必备工具!免费一键批量下载无水印视频 + 一键提取抖音视频文案

抖音创作者必备工具!免费一键批量下载无水印视频 + 一键提取抖音视频文案

XiaoqiangClub的博客 3367

JDBC这个问题,问的小伙伴一脸懵逼

关注“Java后端技术全栈”回复“面试”获取全套面试资料背景前两天一个小伙伴面试的时候,被问JDBC底层是如何连接数据库的?他顿时一脸懵逼,因为大部分人只知道JDBC的几个步骤,至于底层...

田维常 603

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

面试被问java线程状态,一脸茫然?莫慌!看完这篇 从容应对!

面试被问java线程状态,一脸茫然?莫慌!看完这篇 从容应对!Java的线程状态线程方法停止线程线程休眠线程礼让线程强制执行线程状态观测线程的优先级守护(deamon)线程 Java的线程状态 线程方法 方法 说明 setPriority(int newPriority) 更改线程的优先级 static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠 void join() 等待该线程终止 static void yield() 暂停当.

Delilah_java的博客 712

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

面试官:你知道java类是怎么跑起来的吗?问的我一脸懵

面试官:你知道java类是怎么跑起来的吗?问的我一脸懵

qq_41490913的博客 132

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

你要敢问我HashMap,那我绝对让你一脸懵逼 建议收藏

文章目录①. hashCode方法返回值是int类型②. HashMap的综合效率是如何保证的-空间换时间③.HashMap算法①. h = hashCode ^ (hashCode >>> 16)的理解②. 为何不直接使用hashCode值来跟数组长度取模?③. 为什么index = h & (length-1) 要减去1?④. hashMap的二倍扩容⑤. 这有1000个非重复的键值对要存储,我需要怎么初始化我的HashMap?⑥. 高并发情况下扩容时的循环死链,Java8如

所得皆惊喜 1382

阿里面试官问我Spring是如何解决循环依赖的时候,我一脸懵逼了

然后将实例化完成的B对象递归的返回,此时就会将该实例注入到A对象中,这样就得到了一个成品的A对象。从图中我们可以很清楚的看到,B对象的a属性是在第三步中注入的半成品A对象,而A对象的b属性是在第二步中注入的成品B对象,此时半成品的A对象也就变成了成品的A对象,因为其属性已经设置完成了。这里的doGetBean()方法是非常关键的一个方法(中间省略了其他代码),上面也主要有两个步骤,第一个步骤的getSingleton()方法的作用是尝试从缓存中获取目标对象,如果没有获取到,则尝试获取半成品的目标对象;

2401_84439337的博客 560

信心满满去面美团,结果被JVM9连问怼的一脸懵逼

前言 相信很多人一开始接触 Java 虚拟机只是因为面试需要用到,所以硬着头皮去学。所以很多人对于为什么要学虚拟机这个问题,一致的答案皆是:因为面试。(我也是)‘手动狗头’。 大家先来看看JVM9连问大家能答出几问: 反正小编当时被怼的一脸懵逼 其实学习JVM并不仅仅在于面试,而在于更深入地理解 Java 这门语言,以及为未来排查线上问题打下基础。下面我们来看看官方的定义。 随着Java以及Java社区的不断壮大,Java也早已不再是简简单单的一门计算机语言了,它更是一个平台、一种文化、一

m0_64926671的博客 1670

面试被问到“零拷贝”?我一脸懵逼!

面试被问到“零拷贝”?我一脸懵逼! 前言 I/O概念 1.缓冲区 2.虚拟内存 3.mmap+write方式 4.sendfile方式 Java零拷贝 1.MappedByteBuffer 2.DirectByteBuffer 3.Channel-to-Channel传输 Netty零拷贝 其他零拷贝 总结 前言 从字面意思理解就是数据不需要来

Jaylon Wang的专栏 229

面试问你Spring如何解决循环依赖的时候,不要一脸懵逼了!

在关于Spring的面试中,我们经常会被问到一个问题,就是Spring是如何解决循环依赖的问题的。这个问题算是关于Spring的一个高频面试题,因为如果不刻意研读,相信即使读过源码,面试者也不一定能够一下子思考出个中奥秘。本文主要针对这个问题,从源码的角度对其实现原理进行讲解。 1. 过程演示 关于Spring bean的创建,其本质上还是一个对象的创建,既然是对象,读者朋友一定要明白一点就是,一个完整的对象包含两部分:当前对象实例化和对象属性的实例化。在Spring中,对象的实例化是通过反射实现的,而对象

weixin_49527334的博客 170

java面试问jdbc吗,面试被问:JDBC底层是如何连接数据库的?一脸懵逼哇

背景前两天一个小伙伴面试的时候,被问JDBC底层是如何连接数据库的?他顿时一脸懵逼,因为大部分人只知道JDBC的几个步骤,至于底层到底是怎么连接数据库的,还真不知道。由于小伙伴是面试高级开发,问这种问题倒也不能说面试官过分,如果是初级或者中级,那问着问题就确实有些过分了。但是如果你在初级或者中级的阶段,就知道了答案,岂不是爽歪歪么?估计大部分人都不知道这个问题该怎么回答,稍微发散一下思维,倒是可以...

weixin_42517137的博客 402
上一篇: 面试官放大招!一波ZooKeeper灵魂27连问(附答案),这谁顶得住?
下一篇: 能不能整明白分布式系统,关键在于你对Zookeeper理解有多深!
加班不秃顶
博客等级 码龄7年 1822粉丝 599原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值