京东 北京 java 中级: 哪些情况下的对象会被垃圾回收机制处理掉? 哪些对象可以被看做是 GC Roots 呢?对象不可达,一定会被垃圾收集器回收么?

        我同学最近在面试java的岗位, 这是他遇到的某些关于java的JVM中垃圾回收相关的部分的问题, 他来问我, 我特以此文章来解答.

公司  京东

base  北京

面试时间  2024年10月23日16:00:00



        他跟我说, 面试官一上来就问了一个关于JVM的问题, 直接就给他难住了, 问题是 :

 哪些情况下的对象会被垃圾回收机制处理掉? 

  • 我同学:  额 .. 这个我不太清楚, 应该是没有对象引用这个对象的时候, 就会被清理掉吧. 
  • 面试官:  确实如此, 但是我怎么知道 某个对象是否被其他对象引用
  • 我同学:  这个我知道(很自信), 使用的是可达性分析法, 如果一个对象存在与GCRoots的  某个节点的引用链中, 那么这个对象就不会被清理. 
  • 面试官: 那么有哪些可以作为GCRoot呢? 
  • 我同学:  吧唧吧唧(只答了几点, 没答全)
  • 面试官:  那一个对象如果不存在关联的引用链, 那么是否会被清除? 
  • 我同学:  这个不太清楚.... 

         其实, 你也知道, 这就是想问, 哪些对象会在下一次GC的时候, 被垃圾回收器回收掉. 本问题的本质就是想问你, 内存中的对象的状态变成什么样的时候, 才会被垃圾收集器认定为, 下次必拿下你.

         在java中, 显然一个对象如果没有被其他任何对象引用, 那么它就是一个可以被回收的对象, 那么我怎么知道一个对象是否被其他对象引用? 

  • 思路一:  对象枚举搜索, 找到虚拟机中所有的对象, 然后逐个对象去扫描, 看里面有哪个对象引用了这个对象, 如果存在一个对象引用了当前对象, 那么就不需要回收, 否则标记为需要清除. 

        这个方法实现起来非常简单, 但是有一个非常严重的问题, 就是他需要扫描所有的对象, 每个对象都要扫描一次, 那么性能消耗是非常大的. 

  • 思路二 : 引用计数法, 给每一个对象添加一个引用计数器, 每当有地方引用这个对象的时候, 就给计数器+1, 引用失效的时候就-1, 通过这个计数器的引用值是否为0来判断是否为可回收对象. 

        这个方法也相对比较简单, 实现起来也比较简单, 仅仅只是需要占用些许内存空间, 判定的效率也非常高(只用去读取这个计数值, 就可以知道是否是需要回收), 但是这个算法有一个缺点, 就是无法判断相互引用的对象, 如下: 

        可以看到外部已经没有任何对象引用这个instance1和这个instance2了, 但是他们的引用计数值都不为0, 因此就会出现误判. 

        但是也不是说这种方法就不能使用, 只要做好额外的处理, 那么这种方法还是很高效的. 

  • 思路三: 可达性分析法, 当前主流的Java商用程序的内存管理子系统, 都是使用的可达性分析法, 具体思路就是, 借鉴于 枚举搜索法, 从一系列的GC Roots作为起点集, 从起点集中的结点开始往下扫描, 扫描走过的路径就被称为 "引用链", 如果这个对象扫描了GC Roots之后, 出现在一条相关的引用链上, 那么这个对象就不能被回收. 

        图中的绿色的引用关系就可以看作为一个引用链. 

        第三种思路, 就完美的解答了哪些对象会被标记为回收的对象: 利用可达性分析算法,虚拟机会将一些对象定义为 GC Roots,从 GC Roots 出发沿着引用链向下寻找,如果某个对象不能通过 GC Roots 寻找到,虚拟机就认为该对象可以被回收掉

         但是这个问题接下来就是第二个问题, 什么是GC Roots? 哪些对象可以被看做是GC Roots?

在Java技术体系里面, 固定可作为GC Roots的对象包括以下几种: 

  1. 虚拟机栈中的本地变量表中引用的对象(每一个线程都有一个私有的虚拟机栈, 虚拟机栈中每次调用一个方法就会创建一个栈帧并且插入到栈中, 这个栈帧中就包括一个变量表, 这个变量表中就可能包含局部变量参数并且引用了这个对象)
  2. 我们知道在方法区中, 存储了类的静态属性, 这个静态属性也可能会引用某个对象.
  3. 方法区中的常量池亦可引用某个对象, 譬如字符串常量池(String Table)里的引用
  4. 本地方法栈同虚拟机栈, 只不过本地方法栈运行的是一些c/c++编写的代码, 这其中也可能包含对象的引用.
  5. 上述所说都是用户运行程序产生的数据, JVM本身内部也包含很多类对象, class对象, 包含对其他对象的引用.
  6. 当线程持有某个对象的锁时(即使用synchronized关键字修饰的代码块或方法), 该对象就被视为活跃的, 并且可能被其他线程通过锁机制进行访问. 因此, 这个对象在垃圾回收过程中不能被轻易回收, 否则可能会导致持有该锁的线程出现异常或死锁等问题

         紧接着面试官就问了, 如果一个对象不存在于GCRoots的任何一个引用链, 那么下次垃圾回收, 它一定会被清除吗? 

        如果你用过ThreadLocal的话, 那么你就会知道, ThreadLocalMap中的ThreadLocal类型的key是弱引用, 如果被回收, 那么ThreadLocalMap中的对应Key将变为null, 但Value仍然保持强引用, 且无法被GC回收, 从而导致内存溢出(内存泄漏). 

        这里出现了一个关键字, 就是弱引用, 由弱引用, 可以引出Java的四大引用.

 Java四大引用是怎么来的?  

        作为一个Java开发, 你应该知道, 有些对象不是缺了就不行, 但是也不是有就一定行, 我们上述讲解的Java, 抛开四大引用的概念, 就只有一个"引用"的概念, 也就是引用了就必然不会被回收, 但是事实上, 很多场景会出现内存不足的情况, 那么就需要把那些虽然引用了, 但是可以不要的对象给清理掉, 以节省内存空间, 因此就出现了四大引用的概念

        四大引用介绍如下: 

  1. 强引用

    • Java中最常见的引用类型,默认声明时使用的就是强引用。
    • 只要存在强引用指向对象,垃圾回收器就永远不会回收该对象,即使内存不足也不会回收,而是直接抛出OutOfMemoryError错误。
    • 强引用是导致Java内存泄漏的主要原因之一。
  2. 软引用

    • 用于描述一些还有用但非必需的对象。
    • 当内存足够时,软引用对象不会被回收;当内存不足时,系统则会回收软引用对象。如果回收后仍然没有足够的内存空间,则会抛出内存溢出异常。
    • 软引用非常适合实现内存敏感的缓存,如网页缓存、图片缓存等。
  3. 弱引用

    • 用于描述那些非必需的对象
    • 无论内存是否足够,只要JVM开始进行垃圾回收,那些被弱引用关联的对象都会被回收。
    • 弱引用非常适合用于临时缓存或临时存储对象,也可以用于解决对象之间的循环引用问题,避免内存泄漏。
  4. 虚引用

    • 所有引用类型中最弱的一个。
    • 一个对象是否有虚引用的存在,完全不会决定对象的生命周期。也无法通过虚引用来获取被引用的对象。
    • 虚引用的主要作用是跟踪垃圾回收过程,在对象被收集器回收时收到一个系统通知。它必须和引用队列一起使用。

         无论是哪一种引用, 只要是被标记为了清除(对象在进行可达性分析后发现没
有与GC Roots相连接的引用链
),  就会被标记一次, 然后进行筛选, 筛选是否可以进行执行finalize()方法, 如果可以执行finalize()方法(该对象覆盖了Object的finalize()方法, 并且还未执行过finalize()方法), 这个对象就会被放入到一个F-Queue的队列中, 等待一个执行线程来执行这个finalize()方法

        请注意这里的执行, 仅仅只是执行, 并不保证一定执行到代码的最后一行并返回, 因为覆盖的finalize()方法中包含用户代码, 如果代码逻辑出现问题, 会在一定程度上造成执行缓慢的情况, 甚至是死循环, 将很可能导致F-Queue队列中的其他对象永久处于等待. 

        只要在执行的过程中, 对象自我拯救成功:  otherObjcet = this; 也就是将自己赋值给另外一个引用变量, 让其存在对应的引用链

        就可以逃脱此次的回收, 直到下一次回收(下一次回收因为finalize方法已经被执行了, 因此直接就会被回收, finalize在对象的生命周期中, 只能被执行一次)

        自我拯救的代码如下: 

public class FinalizeEscapeGC {public static FinalizeEscapeGC SAVE_HOOK = null;public void isAlive() {System.out.println("yes, i am still alive :)");}@Overrideprotected void finalize() throws Throwable {super.finalize();System.out.println("finalize method executed!");FinalizeEscapeGC.SAVE_HOOK = this;}
}

        这样也就完美的回答了面试官的那个问题: 

即使不可达,对象也不一定会被垃圾收集器回收,1)先判断对象是否有必要执行 finalize()
方法,对象必须重写 finalize()方法且没有被运行过。2)若有必要执行,会把对象放到一个
队列中,JVM 会开一个线程去回收它们,这是对象最后一次可以逃逸清理的机会。

        请注意, 很多人认为这个 finalize方法可以用来资源释放, 请务必别这么做, 可以使用try-finally来平替, 因为finalize的执行是完全不可预知的, 作为资源最后释放的操作, 如果执行失败, 就可以出现资源泄漏的问题, 是非常严重的bug. 

        finalize方法仅仅只是因为历史原因, 向C++程序员做出的一种妥协..... 

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

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

相关文章

深入理解Qt中的QTableView、Model与Delegate机制

文章目录 显示效果QTableViewModel(模型)Delegate(委托)ITEM控件主函数调用项目下载在Qt中,视图(View)、模型(Model)和委托(Delegate)机制是一种非常强大的架构,它们实现了MVC(模型-视图-控制器)设计模式。这种架构分离了数据存储(模型)、数据展示(视图)和数据操作(委托),使…

通过Python爬虫获取商品销量数据,轻松掌握市场动态

为什么选择Python爬虫? 简洁易用:Python语言具有简洁的语法和丰富的库,使得编写爬虫变得简单高效。强大的库支持:Python拥有强大的爬虫框架(如Scrapy、BeautifulSoup、Requests等),可以快速实现…

【记录】Django数据库的基础操作

数据库连接 在Django中使用 mysqlclient 这个包用于数据库的连接,切换至 Django环境中直接 pip install mysqlclient 安装此包 1 数据库连接配置 在项目目录下的setting.py中配置 DATABASES {default: {ENGINE: django.db.backends.mysql,NAME: mini,#数据库名US…

uniapp修改input中placeholder样式

Uniapp官方提供了两种修改的属性方法&#xff0c;但经过测试&#xff0c;只有 placeholder-class 属性能够生效 <input placeholder"请输入手机验证码" placeholder-class"input-placeholder"/><!-- css --> <style lang"scss" s…

Python的买家秀大揭秘:用代码点亮API数据

在一个充满无限可能的数字世界里&#xff0c;Python侦探正准备开始他的新任务&#xff1a;揭开买家秀API数据的神秘面纱。这不仅是一次技术的挑战&#xff0c;更是一次与时间赛跑的较量。Python侦探&#xff0c;这位编程界的福尔摩斯&#xff0c;打开了他的笔记本电脑&#xff…

C++大坑之——多继承(菱形继承)

文章目录 前言一、多继承是什么&#xff1f;1. 多继承概念2. 多继承语法 二、菱形继承1. 为什么会有菱形继承问题&#xff1f;2. 代码感受菱形继承3. 虚拟继承1&#xff09;虚拟继承概念及语法2&#xff09;虚拟继承的原理 4. 为什么要有虚基表&#xff1f;5. 为什么要有偏移量…

bootloader跳转app卡死(IAP卡死)

1、 关闭所有中断再跳转APP 一般bootloader跳转到APP时要关闭app中用到的中断(防止中断打断程序的运行&#xff0c;导致程序跑飞&#xff09;&#xff0c;那么查看系统中用到的中断&#xff1a;串口中断、滴答定时器中断&#xff0c;所以&#xff0c;跳转之前要关闭这两个中断&…

Vlan和Trunk

VLAN的定义 虚拟局域网&#xff0c;用来在二层网络中隔离广播域不同VLAN的设备在二层网络中无法互相通讯&#xff08;二层隔离技术&#xff09; VLAN的转发过程举例 源MAC字段后加上VLAN TAG字段&#xff0c;其中VLAN ID用来标识VLAN。 PC发送数据帧进入交换机&#xff0c;会…

使用SearXNG-搭建个人搜索引擎(附国内可用Docker镜像源)

介绍 SearXNG是聚合了七十多种搜索服务的开源搜索工具。我们可以匿名浏览页面&#xff0c;不会被记录和追踪。作为开发者&#xff0c;SearXNG也提供了清晰的API接口以及完整的开发文档。 部署 我们可以很方便地使用Docker和Docker compose部署SearXNG。下面给出Docker部署Se…

vscode插件live server无法在手机预览调试H5网页

环境 Window10、vscode&#xff1a;1.94.2、Live Server&#xff1a;v5.7.9、Live Server (Five Server)&#xff1a;v0.3.1 问题 PC端预览没有问题&#xff0c;但是在手机点击链接显示访问失败 排查 1. 是否同一局域网 意思就是电脑、手机是不是访问同一个网络。电脑插得…

微信互助学习平台(lw+演示+源码+运行)

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了微信互助学习平台的开发全过程。通过分析微信互助学习平台管理的不足&#xff0c;创建了一个计算机管理微信互助学习平台的方案。文章介绍了微信互助学习平台的…

论文精读:TiC-CLIP: Continual Training of CLIP Models(一)

论文精读&#xff1a;TiC-CLIP: Continual Training of CLIP Models&#xff08;一) 论文介绍 在多模态学习领域&#xff0c;CLIP&#xff08;Contrastive Language-Image Pre-training&#xff09;模型因其在图像和文本联合嵌入方面的卓越性能而受到广泛关注。然而&#xff0…

【C++】vector(1)

&#x1f608;个人主页: 起名字真南 &#x1f608;个人专栏:【数据结构初阶】 【C语言】 【C】 目录 引言1 vector 的基本知识1.1 vector 的特点 2 vector 的主要功能和操作2.1 vector 的构造2.2 vector 的增删改查2.3 vector 的容量 引言 在C的标准模板库&#xff08;STL&…

MySQL——数据库

什么是数据库 数据库&#xff08;DB , DataBase&#xff09;概念&#xff1a;数据仓库&#xff0c;软件&#xff0c;安装在操作系统&#xff08;window&#xff0c;linux&#xff0c;max&#xff0c;...&#xff09;之上学习数据库最重要的就是学习SQL语句存储500万以下的数据…

鸿蒙HarmonyOS————ArkTs介绍(1)

最近除了人工智能&#xff0c;还有一个很火的HarmonyOS&#xff0c;HarmonyOS是华为公司开发的一款面向全场景的分布式操作系统&#xff0c;旨在为消费者提供跨设备无缝协同体验。它支持多种智能终端设备&#xff0c;包括但不限于智能手机、平板电脑、智能穿戴设备、智能家居设…

<Project-11 Calculator> 计算器 0.3 年龄计算器 age Calculator HTML JS

灵感 给工人发工资是按小时计算的&#xff0c;每次都要上网&#xff0c;我比较喜欢用 Hours Calculator &#xff0c;也喜欢它的其它的功能&#xff0c; 做个类似的。 我以为是 Python&#xff0c;结果在学 javascript 看 HTML&#xff0c;页面的基础还停留在 Frontpage 2000…

【学术论文投稿】自动化运维:解锁高效运维的密钥

【连续三届IEEE出版|EI检索】第三届图像处理、计算机视觉与机器学习国际学术会议&#xff08;ICICML 2024&#xff09;_艾思科蓝_学术一站式服务平台 更多学术会议请看&#xff1a;https://ais.cn/u/nuyAF3 目录 引言 一、自动化运维概述 1. 自动化运维的定义 2. 自动化运…

Qt中使用线程之QRunnable

1、自定义1个子类继承自QRunnable 2、重写run方法&#xff0c;编写子线程的业务逻辑 3、使用QThreadPool的全局方法来开启这个线程 4、线程的回收不需要关注&#xff0c;由QThreadPool处理 5、缺点&#xff1a;无法使用信号槽机制 6、适合一些不需要和主线程通信的耗时的任…

SpringBoot中大量数据导出方案:使用EasyExcel并行导出多个excel文件并压缩zip后下载

文章目录 前言一、控制器层代码二、服务层代码三、代码亮点分析 前言 SpringBoot的同步excel导出方式中&#xff0c;服务会阻塞直到Excel文件生成完毕&#xff0c;如果导出数据很多时&#xff0c;效率低体验差。有效的方案是将导出数据拆分后利用CompletableFuture&#xff0c;…

【图论】(四)最小生成树与拓扑排序

最小生成树与拓扑排序 最小生成树之prim&#xff08;P算法&#xff09;相关概念结题思路拓展 最小生成树之kruska&#xff08;K算法&#xff09;过程模拟程序实现拓展 拓扑排序背景与思路模拟过程程序实现 最小生成树之prim&#xff08;P算法&#xff09; 相关概念 P算法是用…