Java对象的生命周期

2023-11-10

Java对象的生命周期

​ Java语言除了原始数据类型外,还有一种类型被称之为引用类型。对象的创建一般需要使用new关键字,将创建的对象存储在堆上(heap)。而在线程栈中会保留一个指向堆上地址的引用。

下图将展示堆栈之间的具体关系,栈中被分割成一个一个的栈帧(“frames”),其中包含调用树中每个方法的参数和局部变量。

在这里插入图片描述

当实例化一个对象是,如果是一个Integer对象,那么JVM首尝试为此对象找到足够的堆空间 - 在32位JVM上大约12个字节。如果可分配的空间足够,那么就调用构造函数,初始化新分配的对象。最后,JVM在bar变量中存储一个指向该对象在堆内的一个内存地址。

当然这是最好的情况,但是有可能,在执行new操作时,JVM无法寻找到一个合适的空间,那么JVM首先会调用GC(垃圾回收机制)来腾出一部分空间,但是如果还是无法满足创建对象的要求,那么JVM不得不抛出OutOfMemoryError异常并放弃对象的创建。

Garbage Collection

GC(垃圾回收机制)是Java管理对象生命周期的重要组成部分,在Java中你创建对象可以使用new关键字来处理,但是Java中没有提供与之对应的delete关键字来处理对象的销毁操作。这就使得我们的应用程序存在内存耗尽的风险。Java为了避免开发者滥用对象的销毁操作,提供了GC机制,即对象的销毁操作由JVM来自己管理,这样可以帮助开发者,从频繁的对象销毁处理操作中解放出来。

当程序试图创建一个新对象并且堆中没有足够的空间时,垃圾收集器开始工作。当收集器查看堆时,请求线程被挂起,尝试查找程序不再使用的对象,并回收它们的空间。如果收集器无法释放足够的空间,并且JVM无法扩展堆,则new运算符将因OutOfMemoryError而失败。通常会关闭您的应用程序。

Mark-Sweep

垃圾收集的大致分为两种:引用计数扫描标记

  • 引用计数 每次对对象的引用都会使对象的引用次数+1,当对象的引用次数为0时,即代表该对象没被引用,即可以通知GC进行垃圾回收。但是存在一个缺点就是,无法避免循环引用,当A中引用B,B中引用A时,这部分内存将无法被回收。
  • 扫描标记 JVM认为无法访问的对象都是垃圾(不可达对象),可以被GC回收。 JVM会从一个root引用对象开始,遍历对象图标记它能到达的对象,这杯称之为标记。

哪些对象引用可以被称之为root

  • stack 存储在栈中的包含方法参数,方法内局部变量,当前正在执行的操作表达式
  • heap 静态类成员变量

Finalizers

虽然在Java中并没有提供类似C++那样的析构函数,但是Java提供了一个`终结的方法`,这个方法会在对象进行垃圾回收之前进行调用,我们可能会想,GC不是帮我们回收了对象的内存,为什么还要调用`finalize`。要知道,在我们的应用程序中,内存并不是唯一的资源,还有一些其他的资源,比如socket连接,数据库连接,文件句柄的释放。当然还有一些其他的类似调用本地方法时,有时候,我们可能需要使用`malloc`来开辟一段内存空间,但是没用显示的调用`free`,Java是无法处理这些外部内存的。这时`finalize`就派上用场了,可以在`finalize`里面显示处理这些资源的释放操作。

注意: 你可能认为Finalizers是一个简单方便的资源清理工具,但是这可能会出现严重的问题,Finalizers的调用时机并不确定,我们无法决定系统何时来调用Finalizers,因为GC的触发是由JVM来决定。它有可能永远也不触发,当GC还没触发我们的应用程序就退出了,你不敢想象这样会发生什么样的问题。所以,我们针对一些资源的释放,我们尽力显示调用,而不要等到对象销毁时,再处理。可以继承AutoClose接口来处理资源的释放。

对象的生命周期(旧)

简而言之,我们可以采用一张图片来概括:

在这里插入图片描述

对象创建-》初始化-》被使用-》不可达-》被收集

前面的部分,表示对象强可达的时间。

对象的生命周期(新)

在JDK1.2中引入了java.lang.ref包,内置对象的三个新生命周期:

  • 强可达(Strongly Reachable) 当一个对象可以有一个或多个线程可以不通过各种引用访问到的情况,比如我们新创建一个对象,那么创建它的线程对它就是强可达。

  • 软可达(Softly Reachable) 如果一个对象不是强可到达对象,但通过遍历某一软引用可以到达它,则该对象是软可到达 对象。

  • 弱可达(weakly Reachable) 如果一个对象既不是强可到达对象,也不是软可到达对象,但通过遍历弱引用可以到达它,则该对象是弱可到达 对象。当清除对某一弱可到达对象的弱引用时,便可以终止此对象了。

  • 幻想可达(Phantom Reachable)如果一个对象既不是强可到达对象,也不是软可到达对象或弱可到达对象,它已经终止,并且某个虚引用在引用它,则该对象是虚可到达对象。

  • 不可达(Unreachable) 当不能以上述任何方法到达某一对象时,该对象是不可到达 对象,因此可以回收此对象。

在这里插入图片描述

强引用(“Stong” Reference)

​ 强引用在我们的引用程序中,随处可见,就是普通对象的引用,只要我们持有这个引用,并且被引用的对象还存在,就表示对象还存活,也就是在可达性分析中,可以从root对象搜索到该对象。垃圾收集器并不会收集该对象。对于普通对象,如果没有其他的引用关系,只要超过了的引用作用域或者显示的赋值为null,表示该对象可以被垃圾收集器收集了。

​ 这里需要强调两点,第一是:在一般情况下,我们调用方法都会在内部声明一些局部变量或提供一些入口参数,一旦这些方法调用结束,即代表着超出了引用的作用域,那么即代表失去了root,对象将有可能变得不可达。第二是:如果显示赋值为null,则表示被引用的对象,与持有对象引用的变量之间失去联系,没有变量再指向该对象,也变得不可达。

软引用(“Soft” Reference)

	弱引用比强引用相对弱化一些,可以让对象豁免一部分的垃圾收集。如果一个referent 是一个软引用并且没有被强引用时,当JVM认为内存不足时,才会尝试回收这些软引用指向的对象。JVM提供的保证是,在抛出`OOM`之前,清理这部分引用的对象。但是,当JVM能恢复到足够的内存时,变不会再清除这部分内存了,因此一个软引用对象可以在`一次`甚至是`多次`的垃圾回收中幸存。

​ JDK文档明确指示,软引用通常用来实现内存敏感的缓存,如果还有空闲内存,就可以暂时保留缓存,当内存不足时再清理掉部分缓存,这样即可以避免内存被耗尽,也可以使缓存可用。

​ 软引用在Android中作为bitmap缓存应用得比较广泛。还有一个应用是,作为断路器,试想一下,当你从某处获取数据,比如数据库或者本地文件中,一次性加载全部的数据,这样有可能导致OutOfMemoryError。我们可以持有一个数据的软引用避免OOM

弱引用(“Weak” Reference)

​ 弱引用并不能豁免垃圾收集,仅仅提供一种访问在弱引用状态下的对象途径,如果没有对referent 的强引用或软引用,它几乎可以保证被收集。它有两个主要的用途:关联没有固定联系的对象,通过规范化Map( canonicalizing map.)消除重复引用。

​ canonicalizing map是关联两个没有固定关系对象的有效手段。也就是维护一种非强制的映射关系,当你获取一个对象时,如果对象还存在就使用它,没有则重新实例化,并将其放入这个映射中。String.intern()就是一个该应用的经典实现,这样能有有效避免重复字符串消耗内存。而且并不依赖key,value 的映射关系,代表 同一个Key所映射的value是可变的,这种可变体现在,当value被内存回收后,会出现一个新的value来替代原来的value。而对于程序本身来说并没有什么大影响,除非你在比较value的hash值。

幻像引用(“Phantom” Reference)

​ 幻像引用也被称作为虚引用或幽灵引用。你不能通过它来访问对象(referent ),因为它永远返回null,通过虚引用可到达的对象将仍然保持原状,直到所有这类引用都被清除,或者它们都变得不可到达。也就是虚引用一旦被引用,那么它的状态将无法被改变。它的唯一目的是告诉你他们的(referent )何时被收集。但它实际上允许您执行资源清理,其灵活性比从终结器获得的更灵活。

​ 比如:它可以用来做些Post-Mortern清理机制,以及Clean机制,还可以用来监控对象的创建和销毁。

引用队列(ReferenceQueue)

​ ReferenceQueuen一般是与各种引用相关联的,我们在创建各种引用时可以显示的关联到对应的引用队列,JVM会在特定的时机将引用enqueue到队列,我们可以从队列中获取引用,然后进行处理。ReferenceQueue一般会与幻象引用结合使用,因为幻象引用只能返回null,我们可以使用队列判断,幻象引用所引用的对象是否已经销毁,从而确定对象的生命周期。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java对象的生命周期 的相关文章

  • linux命令之ssh详解

    ssh openssh套件中的客户端连接工具 Linux在线工具 linux命令在线工具 个人博客网站 博客 Java17中文文档 JDK17中文手册 Gradle8 1 1中文文档 Gradle中文文档 补充说明 ssh命令 是opens
  • (转载)Linux 系统内核的调试

    调试是软件开发过程中一个必不可少的环节 在 Linux 内核开发的过程中也不可避免地会面对如何调试内核的问题 但是 Linux 系统的开发者出于保证内核代码正确性的考虑 不愿意在 Linux 内核源代码树中加入一个调试器 他们认为内核中的调
  • PHP实现微信小程序状态检测(违规、暂停服务、维护中、正在修复)

    实现原理 进入那些状态不正常的小程序会被重定向至一个Url 使用抓包软件抓取这个Url 剔除不必要参数 使用cURl函数请求网页获得HTML内容 根据内容解析出当前APPID的小程序的状态 代码
  • thrust库学习(一) —— cub::DeviceRadixSort

    1 cub DeviceRadixSort 1 1 介绍 DeviceRadixSort提供设备范围内的并行操作 用于跨驻留在设备可访问内存中的数据项序列计算基数排序 基数排序方法按升序 或降序 排列项目 该算法依赖于键的位置表示 即每个键
  • LeetCode-动态规划-路径的数目

    1 题目 剑指 Offer II 098 路径的数目 62 不同路径 2 实现 class Solution public vector
  • 原生js方法小记

    ps 无框架时 使用js的一些功能完成一些小demo 记录方法 方便自己查询 原生js方法小记 String 和Array 方法 替换所有 追加replaceAll方法 String prototype replaceAll functio
  • spring提供的登录j_spring_security_check

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 第一步 form表单提交
  • 芯片中的上百亿个晶体管是如何设计的?

    2021年4月21日 在芯片界的顶级会议Hot Chips大会上 Cerebras Systems公司发布了一款晶圆级引擎芯片 Wafer Scale Engine 2 这款芯片采用台积电7纳米工艺制程 拥有85万个AI核心 包含2 6万亿
  • 如何在html中把按钮设置为超链接

    如何给按钮加上链接功能 脚本说明 把如下代码加入区域中
  • 【Spring】Spring之publishEvent

    观察者模式Spring之publishEvent事件处理 1 使用场景 这个一般什么时候使用 我们一般是在不同的bean直接进行信息传递 比如我们beanA的事件处理完后 需要beanB进行处理一些业务逻辑的时候这种情况就一般可以使用pub
  • 在Linux(Ubantu)下用 PNNX 转换 TorchScript 模型到 ncnn 模型

    初次使用 PNNX 的相关步骤记录 目的 转换 PyTorch 的 TorchScript 格式的模型文件到 ncnn 的模型文件 环境 操作系统 Windows Ubuntu macOS 均可 pnnx和pytorch都是跨平台的 Pyt
  • 系统检测到您的账户不符合国家相关法律法规或《支付宝用户服务协议》约定

    改用个人账户登录 需要上传营业执照 这样就成功了
  • 权限设计=功能权限+数据权限

    权限管理 Authority Management 目前主要是通过用户 角色 资源三方面来进行权限的分配 具体来说 就是赋予用户某个角色 角色能访问及操作不同范围的资源 通过建立角色系统 将用户和资源进行分离 来保证权限分配的实施 一般指根
  • 逆向爬虫01 requests模块

    python requests模块 requests是一个python模拟浏览器发送http请求的模块 1 使用requests模块发送get请求 获取网页源代码 import requests url http www baidu com
  • strictfp有什么作用

    关键字 strictfp 是 sitict float point 的缩写 指的是精确浮点 它用来确保浮点数运算的准确性 JVM 在执行浮点数运算时 如果没有指定 strictip 关键字 此时计算结果可能会不精确 而且计算结果在不同平台或
  • 一不小心就弄懂了 冒泡,选择,插入,希尔,归并和快速排序

    今天我们主要看一些简单的排序 常见的时间复杂度 常数阶 1 对数阶 log2n 线性阶 n 线性对数阶 nlog2n 平方阶 n 立方阶 n K次方阶 n k 指数阶 2 n 常见的时间复杂度对应图 1 log2n n nlog2n n n
  • PKU2019暑期学堂 游记

    诈尸写博客QaQ 一塔湖图 Day 0 18 00 从学校出发 with另外三个同学 前往南站 20 20上动车 感觉人好少的样子 房间灯是坏的 还换了一间 在火车上刷知乎 提前体验一下夏令营 而其他人都在弯道QwQ 好多人水群啊QwQ D
  • 新手入门 哪个视频剪辑软件好用

    当下 视频剪辑已成为一种全新记录生活的方式 许多人剪辑视频都是从零基础开始学习 那么从入门开始选择的软件就显得比较重要了 今天在这里给大家推荐一款适合新手入门的视频剪辑软件 会声会影 图1 会声会影软件 会声会影是一款很亲民的视频剪辑软件
  • C语言

    include

随机推荐

  • vue实现页面停留时间统计

    前言 在实际业务中 埋点需求是前端开发中非常重要的数据指标获取的方式之一 今天 主要聊一下页面停留时间的统计 简略版 每个页面独自实现相关统计 并上报数据 export default data return startTime 0 cre
  • SQL注入-联合注入

    页面有显示位时 可用联合注入 本次以 SQLi 第一关为案例 第一步 判断注入类型 参数中添加 单引号 如果报错 说明后端没有过滤参数 即 存在注入 id 1 从数据库的报错中我们可得知 最外边的一对单引号是错误提示自带的 我们不用管 我们
  • pip install -r requirements.txt报错ERROR解决办法

    这个问题困扰了我很长时间 因为做的时候没有保存错误的截图 所以只能写一些思路 1 首先是vscode的环境 然后在里面安装Build Tools 这个很重要 否则会一直报错 安装包图片是上面这两个 下载的话Visual Studio Cod
  • 脚本收集服务器信息,shell脚本批量收集linux服务器的硬件信息快速实现

    获取默认IP default ip ifconfig head n 2 tail n 1 cut d f 2 cut d f 1 获取产品的名称 如果是简化版的linux系统 需要先安装dmidecode工具包 product name d
  • java高并发的处理--锁机制

    对于我们开发的网站 如果网站的访问量非常大的话 那么我们就需要考虑相关的并发访问问题了 而并发问题是绝大部分的程序员头疼的问题 但话又说回来了 既然逃避不掉 那我们就坦然面对吧 今天就让我们一起来研究一下常见的并发和同步吧 为了更好的理解并
  • phpstudy小皮 sqli-libs 靶场搭建

    sqli libs靶场搭建 1 下载靶场 sqli labs mster https github com Audi 1 sqli labs archive refs heads master zip 解压 2 下载 安装 phpstudy
  • Python(解非线性方程和线性方程)求水力学法向深度-浪涌高度速度及互连反应器中的浓度和流体分布

    非线性方程 在水力学领域遇到的非线性方程的一个例子是通过长梯形通道寻找流动的法向深度 y n y n yn 这样的流动深度出现在均匀流动区域 远离任何不均匀原因的影响 例如堰的上游 法向深度 y
  • 《GPT-4技术报告》【中文版、英文版下载】

    大预言模型时代已经到来 但是真正的智能之路还很长 一 以下是连接 大家请自取 英文原版 https arxiv org pdf 2303 08774 pdfhttps arxiv org pdf 2303 08774 pdf 中文翻译版本
  • 最大信息系数mic python_生物信息学

    论文剖析 热门论文 AgeGuess 一种预测人类年龄的甲基化模型 1 介绍 衰老是一个生物过程 受到遗传因子和细胞内各种分子修饰的影响 多项研究表明 使用甲基组数据可以准确预测实际年龄 本篇文章针对年龄回归问题 提出了一种三步特征选择算法
  • 【SpringBoot】pom中的变量

    在Maven项目的pom xml文件中 可以使用多个预定义变量 以下是一些常用的变量 project basedir 项目根目录的绝对路径 project build directory 构建目录的绝对路径 通常为target projec
  • mybatis_plus

    目录 一 简介 二 特性 三 快速入门 一 创建并初始化数据库 1 创建数据库 2 创建 User 表 二 初始化工程 三 添加依赖 1 引入依赖 2 idea中安装lombok插件 四 配置 五 编写代码 1 主类 2 实体 3 mapp
  • [ERROR] Can't open the mysql.plugin table. Please run mysql_upgrade to create it.(入职小灰)

    mariadb剧本安装后自动重启不了 飞要一次手动重启 这对于重要业务来说是致命的 今天遇到的错误 ERROR Can t open the mysql plugin table Please run mysql upgrade to cr
  • threejs教程(一)

    插件安装 npm i three 项目引入 这里我随便找的VUE项目练习的 import as THREE from three 大致介绍一下threejs的逻辑 一般我们用它是来搭建三维模型的 搭建三维模型就需要的三个要素 场景 scen
  • 【Xilinx Vivado 时序分析/约束系列11】FPGA开发时序分析/约束-FPGA DDR-PLL接口的 input delay 约束优化方法

    目录 DDR PLL 简述 实际操作 实际工程 顶层代码 PLL配置 添加时钟约束 添加 input delay 约束 添加 False Path Setup Time Hold Time Multicycle约束 解决办法 PLL配置 发
  • css transition 实现滑入滑出

    transition是css最简单的动画 通常当一个div属性变化时 我们会立即看的变化 从旧样式到新样式是一瞬间的 嗖嗖嗖 但是 如果我希望是慢慢的从一种状态 转变成另外一种状态 怎么办 transition可以做到 第一问 哪些属性值变
  • 电脑连着无线wifi(外网)和有线内网,如何实现双网访问?

    做交付难免会遇到 需要开发远程解决问题 但是客户方是内网 开发无法远程 因为自己遇到很多次 记性又差 所以就写着给自己看看 以管理员身份运行命令提示符 场景描述 访问地址 http 172 31 27 15 内网必须要可以访问这个地址 内网
  • CUID卡写入错误数据被锁死——入坑NFC的一段经历

    最开始想到做NFC是还在学校上自习的时候 学校有种氛围很好的自习室 每个位置都是一个小隔间 小隔间里还有小灯和插座以及网线口 但是需要插卡取电 对就是用很普通的那种校园卡插进去就有电了 这个校园卡是NFC卡 但是学校很nt的一点是只有上一届
  • vue 项目中通过监听 localStorage 的变化进行父子页面传参

    vue实时监听 localStorage 变化 应用场景 1 页面B需要实时获取页面A数据更改 2 父子页面之间的传参 代码实例 B页面实时获取A页面的数据变化 在 页面A 进行缓存修改or插入缓存 localStorage setItem
  • MySQL8.0_JDBC笔记

    第一章 JDBC概述 之前我们学习了JavaSE 编写了Java程序 数据保存在变量 数组 集合等中 无法持久化 后来学习了IO流可以将数据写入文件 但不方便管理数据以及维护数据的关系 后来我们学习了数据库管理软件MySQL 可以方便的管理
  • Java对象的生命周期

    Java对象的生命周期 Java语言除了原始数据类型外 还有一种类型被称之为引用类型 对象的创建一般需要使用new关键字 将创建的对象存储在堆上 heap 而在线程栈中会保留一个指向堆上地址的引用 下图将展示堆栈之间的具体关系 栈中被分割成