JVM 一个对象是否已经死亡?

目录

前言

引用计数法

可达性分析法 

引用

finalize() 

方法区回收


前言

        虚拟机中垃圾回收器是掌握对象生死的判官, 只要是垃圾回收器认为需要被回收的, 那么这个对象基本可以宣告"死亡".  但是也不是所有的对象, 都需要被回收, 因此, 我们在学习垃圾回收的时候, 应该多思考思考下面几个问题: 

  • 哪些对象需要回收
  • 什么时候回收
  • 怎么回收

        JVM的自动回收对使用者来说是透明的, 但是自动也并不代表是万能的, 在某些特定的场景, 垃圾回收甚至可以成为系统的瓶颈.  垃圾回收的不确定性是我们需要去了解的, 以便写出更好的程序. 

        其实我们都知道 只要一个对象赋值给一个引用变量, 就不会被垃圾回收器回收, 例如: 

Object obj = new Object();

        obj这个引用变量持有了这个对象的引用. 因此不会被回收, 但是事实却没有那么简单. 比如, 加入一个对象A持有了另外一个对象B的引用, 那么B就不会被回收吗? 并不会, 虽然对象B被A引用了, 但是对象A没有被任何对象引用, 也就是说A是会被回收的对象, 那么A中对B的引用也将会失效, 因此B也应该被回收.

        因此垃圾回收的机制不会辣么随意, 如果这么随意的话, 也不会到现在还在流行.. .. 


引用计数法

        引用计数法是一个非常简单的判断对象是否被引用的案例, 原理很简单, 就是如果一个对象被引用, 那么其计数器就+1, 若计数器的值为0就说明没有地方引用他, 因此此时可以被回收. 

        但是这种方法有一种致命的问题, 那么就解决不了复杂场景的循环引用的问题. 例如对象A中的变量引用了对象B, 对象B中的变量引用了对象A, 那么他们互相持有相互的引用, 因此A和B的引用计数器都为1, 但是考虑另外一种情况, 也就是A和B以及脱离系统了, 以及用不上了, A和B可以一起被回收

        举一个不恰当的例子, 例如你有一个游戏机套装, 里面有手柄和主机, 主机没了手柄不能游玩, 手柄离开了主机, 也没有任何意义, 他两相互依赖, 但是这并不会阻止你在某一天将其卖给第三方或者扔进垃圾桶. 

        但是这种计数法也不是一无是处. 它的原理简单,判定效率也很高,在大多数情况下它都是一个不错的算法。也有一些比较著名的应用案例,例如微软COM(Component Object Model)技术、使用ActionScript 3的FlashPlayer、Python语言以及在游戏脚本领域得到许多应用的Squirrel中
都使用了引用计数算法进行内存管理. 

        但是就Java这种会拥有复杂的引用关系的来说, 基本是舍弃了这种方法. 


可达性分析法 

        这种算法的基本思路就是通过一系列引用结点开始向下搜索, 如果一个对象存在于这个依赖链中, 那么它就不应该被回收, 如下: 

         图中Object5以及其子引用obj6和obj7都不可达到其GC Roots, 也就意味着系统中没有使用到他们的地方了, 因此此时他们可以一起打包回收了 . 

        我们仔细回想一下, 哪些可以对象可以作为GC Roots, 

  • 虚拟机栈中的局部变量表中的局部变量, 参数等: 

  • 在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量
  • 在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用 
  • 本地方法栈中引用的java对象
  • Java虚拟机内部的引用
  • 所有被同步锁(synchronized关键字)持有的对象

引用

        如果一个对象只能被标记为可回收和不可回收, 那么就过于绝对了, 因为肯定还存在一些, 可以被回收, 也可以不被回收的对象, 最简单的一个例子就是缓存, 内存不够的时候, 可以清除缓存给主程序让路, 内存够的时候, 缓存可以为系统提速. 

        因此JDK1.2后续版本新增对引用概念的扩充. 如下: 

  • 强引用, 如Object tem = new Object(); 只要强引用关系还存在, 就会被回收
  • 软引用, 弱于强引用, 用来描述, 还有用, 但是非必要对象, 只要被软引用管理关联的对象, 在系统发生溢出前, 这些对象就是下一次被回收的对象. 如果这部分引用的对象被回收了还是溢出, 那么就会OOM, 在JDK 1.2版之后提供了SoftReference类来实现软引用
  • 弱引用, 描述那么非必须的对象, 下一次GC, 无论内存是否足够, 都会被回收. 在JDK 1.2版之后提供了WeakReference类来实现弱引用
  • 虚引用: 最弱的引用关系一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知。在JDK 1.2版之后提供了PhantomReference类来实现虚引用。

finalize() 

        即使在可达性分析算法中判定为不可达的对象,也不是“非死不可”的. 真正宣告一个对象死亡, 需要经历两次标记过程. 如果对象在进行可行性分析后发现没有与GC Roots 相连接的引用链, 那么就会被第一次标记, 随后进行一次筛选, 筛选的条件就是此对象是否有必要执行finalize方法, 假如对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,那么虚拟机将这两种情况都视为没必要执行finalize方法.  (相当于直接被确认回收的对象)

        因为finalize方法只会被调用一次, 因此已经被调用过的, 还有没有重写finalize, 都不会去执行finalize这个方法了, 被第一次标记的对象, 并且覆盖了finalize, 并且还没有被执行过的, 就会被定义为确有必要执行finalize()方法. 该对象就会被放入一个叫做FQueue的队列中, 并在稍后由一个java虚拟机创建的线程去执行这个队列里面的对象的finalize方法. 但是这个线程的调度级别很低.

        这个线程被称为: Finalizer线程, 它执行finalize的方法的时候, 并不保证能完整执行完结束, 因为考虑finalize方法本身运行缓慢或者出现死循环, 就会导致FQueue里面的对象的finalize方法难以得到有效执行. 甚至导致整个内存回收子系统的崩溃.

        在这个finalize里面, 这个对象将有机会脱离死亡, 收集器将对FQueue中的对象进行第二次小规模的标记只要重新与引用链上的任何一个对象建立关联即可.  例如将this关联给其他变量, 如果这个阶段还没有被引用, 那么就会被回收.

        考虑如下代码, SAVE_HOOK 在一开始赋值了一个FinalizeEscapeGC对象, 然后又舍弃了这个对象, 随后调用GC, 然后在GC执行的时候, 就会像上述那样去看finalize()是否被覆盖和被调用过一次, 这里显然没有被调用, 因此就会由Finalizer线程去执行finalize方法, 这个方法里面将自己的引用再次赋值给SAVE_HOOK, 保证了这个对象重新被引用, 因此第一次回收还存活. 

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;}public static void main(String[] args) throws Throwable {SAVE_HOOK = new FinalizeEscapeGC();
//对象第一次成功拯救自己SAVE_HOOK = null;System.gc();
// 因为Finalizer方法优先级很低,暂停0.5秒,以等待它Thread.sleep(500);if (SAVE_HOOK != null) {SAVE_HOOK.isAlive();} else {System.out.println("no, i am dead :(");}
// 下面这段代码与上面的完全相同,但是这次自救却失败了SAVE_HOOK = null;System.gc();
// 因为Finalizer方法优先级很低,暂停0.5秒,以等待它Thread.sleep(500);if (SAVE_HOOK != null) {SAVE_HOOK.isAlive();} else {System.out.println("no, i am dead :(");}}
}

        第二次就没那么幸运了, 因为finalize已经被调用了, 因此第一次被标记的时候, 筛选它有没有finalize或者是否已经被执行的时候, 就已经确认了他要被回收了. 

        这里其实并不推荐使用这种方法(finalize), 很多地方说是回收资源, 像try-catch那样, 我觉得很牵强,  因为其不确定性, 官方也说了不推荐. 


方法区回收

        我们之前已经学习过了, 方法区用来存放常量池, 类名, 各种类的信息等数据, 这些东西都是在编译的时候确定好的(即使是一些动态类的扩展类, 也基本可以在运行时确认), 相比于堆区, 方法区回收的收益非常低, 堆区中由于经常新建和销毁对象, 因此收益比较高, 尤其是在新生代中,对常规应用进行一次垃圾收集通常可以回收70%至99%的内存空间 .

        方法区主要手机的内容是 废弃的常量和不再使用的类型. 回收废弃常量与回收Java堆中的对象非常类似, 例如一个字符串str 在常量池中, 但是没有任何一个系统的变量值为str的值, 也就是说已经没有了任何字符串对象引用常量池中的str字符串常量, 虚拟机中也米有其他地方需要引用这个字面量,  此时发生回收, 这个字面量字符串就会被回收, 常量池中其他的类, 接口, 方法的定义也是如此, 

        常量好判断, 那么不再被使用的类呢? 一个类被使用就得看它是不是有实例对象, 但是没有实例对象的类, 也不一定就不会被再次使用. 但是一般的需要遵循下面这是三个步骤: 

  1. 该类的所以实例都被回收, 并且也不得有其派生的子类的对象
  2. 该类的类加载器已经被回收
  3. 该类的Class对象没有被任何地方引用, 任何地方都不得使用其Class对象来进行反射访问该类的方法.

        达到这个三个条件的类才允许被回收. 

        

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

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

相关文章

Qt开发技巧(四)“tr“使用,时间类使用,Qt容器取值,类对象的删除,QPainter画家类,QString的转换,用好 QVariant类型

继续讲一些Qt技巧操作 1.非必要不用"tr" 如果程序运行场景确定是某一固定语言,就不需要用tr,"tr"之主要针对多语种翻译的,因为tr的本意是包含英文,然后翻译到其他语言比如中文,不要滥用tr,如果没有…

万字长文——ConvNeXt(2022CVPR),卷积网络的顶峰之作,在Transformer盛行的当下,卷积网络还能再战!

ConvNext:A ConvNet for the 2020s ConvNext:2020 年代的卷积神经网络 论文地址: https://arxiv.org/pdf/2201.03545 自从Transformer成功应用在视觉领域并且取得显著成绩后,很多人开始抛弃卷积网络架构,转而使用Transformer。然而有的大佬不认为卷积过时了,于是有了这篇…

OpenGL渲染管线(Rendering Pipeline)介绍

渲染管线 计算机图形学中,计算机图形管线(渲染管线 或简称 图形管线、流水线)是一个概念模型,它描述了t图像系统将 3D场景渲染到2D屏幕所需执行的一系列步骤。渲染管线大的可以分为三个阶段。 (一)应用阶段…

Web接入Sonic平台之安装

问题及解决方案 1.安装python的airtest-bdd依赖时报错,显示无法编译psutil note: This error originates from a subprocess, and is likely not a problem with pip. ERROR: Failed building wheel for psutil Failed to build psutil ERROR: ERROR: Failed to b…

Android SystemUI组件(07)锁屏KeyguardViewMediator分析

该系列文章总纲链接:专题分纲目录 Android SystemUI组件 本章关键点总结 & 说明: 说明:本章节持续迭代之前章节的思维导图,主要关注左侧上方锁屏分析部分即可。 为了更好理解本文的内容,优先说明下SystemUI中与Ke…

[已更新前两问代码+全部建模]2024华为杯C题详细思路代码文章建模分享研究生数学建模竞赛数学建模研赛

截止9.21 12点 已更新问题一二的代码和全部内容的建模 下面我们会先进行代码讲解,之后给出全部内容的建模公式 ## https://docs.qq.com/doc/DVWhyZ1NFY01XcmNw基于磁通密度数据的特征提取与分类分析。 问题一代码详解 1. 导入必要的库 import pandas as pd import numpy as…

Elastic 的 OpenTelemetry PHP 发行版简介

作者:Pawel Filipczak 宣布 OpenTelemetry PHP 的 Elastic 发行版的第一个 alpha 版本。在本篇博文中了解使用 OpenTelemetry 来检测 PHP 应用程序是多么简单。 我们很高兴推出 OpenTelemetry PHP 的 Elastic Distribution 的第一个 alpha 版本。在这篇文章中&…

十九、石英晶体振荡电路

石英晶体振荡电路 1、石英晶体的特点、等效电路、特性曲线; 2、石英晶体振动器的特点, 3、石英晶体振动器的振荡频率

【爱给网-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 1. 暴力破解密码,造成用户信息泄露 2. 短信盗刷的安全问题,影响业务及导致用户投诉 3. 带来经济损失,尤其是后付费客户,风险巨大,造…

滑动窗口算法专题(1)

找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程(ಥ_ಥ)-CSDN博客 所属专栏: 优选算法专题 目录 滑动窗口算法的简介 209. 长度最小的子数组 3.无重复字符的最长子串 1004. 最大连续1的个数III 1658. 将减到0的最小…

Java调用数据库 笔记06 (修改篇)

1.创建Java的普通class类 2.加载驱动 Class.forName("com.mysql.jdbc.Driver"); 3.驱动管理类调用方法进行连接,得到连接对象 DriverManager.getConnection(url, user, password); 其中设置参数: static final String url "jdbc:my…

python中ocr图片文字识别样例(二)

一、说明 本次解决图片相关出现中文乱码问题,属于上篇文章的优化,前提条件依赖上篇文章的包,当然ocr的具体应用场景很多,根据自身需求进行调整 二、具体实现 2.1 代码实现: # -*- coding: utf-8 -*- import easyoc…

电气设备施工现场风险状态判断ai模型训练数据集

电气设备施工现场风险状态判断ai模型训练数据集 id:18 电气设备施工现场工人人工智能学习数据和工作环境安全数据,建立系统化管理体系,改变全球EHS范式,预防工业事故。数据集记录了387709例子电力设施建设以及施工现场相关的灾害安全环境数据…

电力行业螺钉螺帽螺丝缺失检测数据集 voc yol

电力行业螺钉螺帽螺丝缺失检测数据集 数据集描述 该数据集旨在用于电力行业中的螺钉、螺帽、螺丝等紧固件的缺失检测任务。数据集包含了大量的图像及其对应的标注信息,可用于训练计算机视觉模型,以识别和定位电力设施中的螺钉、螺帽、螺丝等部件是否存在…

【零成本】七日杀 服务器搭建 异地联机 无需公网IP、服务器

主要内容 什么是七日杀 搭建前需要准备什么 详细步骤 1.Steam中下载七日杀服务器工具 2.修改七日杀服务配置文件 3.启动七日杀服务器应用 4.运行 MoleSDN 进行异地联机 5.小伙伴打开游戏加入 鼠鼠的服务器 什么是七日杀 《七日杀》是一款沙盒生存恐怖游戏,…

【2025】儿童疫苗接种预约小程序(源码+文档+解答)

博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…

LeetCode[中等] 54.螺旋矩阵

给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 思路:定义方向数组,按照顺时针顺序:右(0,1),下(1,0),左(0,-1),上(0,-1) 从矩阵的左上角开始遍历…

5. 数字证书与公钥基础设施

5. 数字证书与公钥基础设施 (1) PKI 的定义、组成及应用 PKI(Public Key Infrastructure,公钥基础设施) 是一个使用公钥技术来提供安全服务的框架。它定义了如何管理和维护公钥,以及如何通过证书来验证公钥的真实性。PKI的核心组成部分包括: 证书颁发机构(CA, Certifica…

Maven 安装

Maven 安装 Maven 下载安装 下载MAVEN 选择版本注意: IDEA 2022 兼容maven 3.8.1及之前的所用版本 IDEA 2021 兼容maven 3.8.1及之前的所用版本 IDEA 2020 兼容Maven 3.6.3及之前所有版本 IDEA 2018 兼容Maven3.6.1及之前所有版本 打开MAVEN官网 下载需要的版本 Wi…

软件设计师——操作系统

📔个人主页📚:秋邱-CSDN博客☀️专属专栏✨:软考——软件设计师🏅往期回顾🏆:C: 类和对象(上)🌟其他专栏🌟:C语言_秋邱 一、操作系统…