JVM虚拟机系统性学习-对象存活判断算法、对象引用类型和垃圾清除算法

垃圾回收

在 JVM 中需要对没有被引用的对象,也就是垃圾对象进行垃圾回收

对象存活判断算法

判断对象存活有两种方式:引用计数法、可达性分析算法

引用计数法

引用计数法通过记录每个对象被引用的次数,例如对象 A 被引用 1 次,就将 A 的引用计数器加 1,当其他对象对 A 的引用失效了,就将 A 的引用计数器减 1

  • 优点:
    • 实现简单,判定效率高
  • 缺点:
    • 需要单独的字段存储计数器,增加存储空间开销
    • 每次赋值都要更新计数器,增加时间开销
    • 无法处理循环引用的情况,致命问题!即 A 引用 B,B 引用 A,那么他们两个的引用计数器永远都为 1

可达性分析算法

可达性分析算法可以有效解决循环引用的问题,Java 选择了这种算法

可达性分析算法以根对象集合(GC Roots)为起使点,按照从上至下的方式搜索被根对象集合所连接的目标对象是否可达,通过可达性分析算法分析后,内存中的存活对象都会被根对象集合直接或间接连接着,搜索过程所走过的路径称为引用链,如果目标对象没有任何引用链相连,则是不可达的,就可以标记为垃圾对象

GC Roots 主要包含以下几类元素:

  • 虚拟机栈中引用的对象

    如:各个线程被调用的方法中所使用的参数、局部变量等

  • 本地方法栈内的本地方法引用的对象

  • 方法区中引用类型的静态变量

  • 方法区中常量引用的对象

    如:字符串常量池里的引用

  • 所有被 synchronized 持有的对象

  • Java 虚拟机内部的引用

    如:基本数据类型对应的 Class 对象、异常对象(如 NullPointerException、OutOfMemoryError)、系统类加载器

垃圾回收过程

在 Java 中对垃圾对象进行回收需要至少经历两次标记过程:

  • 第一次标记:如果经过可达性分析后,发现没有任何引用链相连,则会第一次被标记
  • 第二次标记:判断第一次标记的对象是否有必要执行 finalize() 方法,如果在 finalize() 方法中没有重新与引用链建立关联,则会被第二次标记

第二次被标记成功的对象会进行回收;否则,将继续存活

对象的 finalization 机制:

Java 提供了 finalization 机制来允许开发人员 自定义对象被销毁之前的处理逻辑,即在垃圾回收一个对象之前,会先调用这个对象的 finalize() 方法,该方法允许在子类中被重写,用于在对象被回收时进行资源释放的工作

对象引用

在 JDK1.2 之后,Java 对引用的概念进行了扩张,将引用分为强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference)、虚引用(PhantomReference)四种,这四种引用强度依次逐渐减弱

  • 强引用-不回收:强引用是最普遍的对象引用,也是默认的引用类型,强引用的对象是可触及的,垃圾回收器永远不会回收被引用的对象,因此强引用是造成Java内存泄漏的主要原因之一

    • 当使用new操作创建一个新对象时,并且将其赋值给一个变量时,这个变量就成为该对象的一个强引用
  • 软引用-内存不足回收:在即将发生内存溢出时,会将这些对象列入回收范围进行第二次回收,如果回收之后仍然没有足够的内存,则会抛出内存溢出异常

    • 软引用通常用来实现内存敏感的缓存,例如高速缓存使用了软引用,如果内存足够就暂时保留缓存;如果内存不足,就清理缓存

      // 创建弱引用
      SoftReference<User> softReference = new SoftReference<>(user);
      // 从软引用中获取强引用对象
      System.out.println(softReference.get());
      
  • 弱引用-发现即回收:被弱引用关联的对象只能存活在下一次垃圾回收之前,在垃圾回收时,无论空间是否足够,都会会受掉被弱引用关联的对象

    • 弱引用常用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的 isEnQueued 方法判断对象是否被垃圾回收器标记

      Object obj = new Object();
      WeakReference<Object> wf = new WeakReference<Object>(obj);
      obj = null;
      // System.gc();
      // 有时候会返回null
      Object o = wf.get(); 
      // 返回是否被垃圾回收器标记为即将回收的垃圾
      boolean enqueued = wf.isEnqueued(); 
      System.out.println("o = " + o);
      System.out.println("enqueued = " + enqueued);
      
  • 虚引用:垃圾回收时,直接回收,无法通过虚引用获取对象实例

    • 为一个对象设置虚引用关联的唯一目的就是能在这个对象被垃圾回收时收到一个系统通知

      Object obj = new Object();
      PhantomReference<Object> pf = new PhantomReference<Object>(obj, new
      ReferenceQueue<>());
      obj=null;
      // 永远返回null
      Object o = pf.get();
      // 返回是否从内存中已经删除
      boolean enqueued = pf.isEnqueued();
      System.out.println("o = " + o);
      System.out.println("enqueued = " + enqueued);
      

垃圾清除算法

GC最基础的算法有三种: 标记 -清除算法、复制算法、标记-压缩算法,我们常用的垃圾回收器一般都采用分代收集算法。

  • 标记-清除算法:在标记阶段,从 GC Roots 开始遍历,标记所有被引用的对象,标记为可达对象,再对堆内存从头到尾遍历,回收没有标记为可达对象的对象(标记清除算法可以标记存活对象也可以标记待回收对象)

    • 这里并不是真正清除,而是将清除对象的地址放在空闲的地址列表中
    • 缺点
      • 效率不高
      • GC 时需要停止整个应用进程,用户体验不好
      • 会产生内存碎片

    在这里插入图片描述

  • 复制算法:它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉

    现在商用的 Java 虚拟机大多都优先采用这种收集算法去回收新生代,如果将内存区域划分为容量相同的两部分太占用空间,因此将复制算法进行了优化,优化后将新生代分为了 Eden 区、Survivor From 区、Survivor To 区,Eden 和 Survivor 的大小比例为 8:1:1,每次分配内存时只使用 Eden 和其中的一块 Survivor 区,在进行垃圾回收时,将 Eden 和已经使用过的 Survivor 区的存活对象转移到另一块 Survivor 区中,再清理 Eden 和已经使用过的 Survivor 区域,当 Survivor 区域的空间不足以容纳一次 Minor GC 之后存活的对象时,就需要依赖老年代进行分配担保(通过分配担保机制,将存活的对象放入老年代即可)

    • 优点
      • 实现简单,运行高效
      • 复制之后,保证空间的连续性,不会出现“内存碎片”
    • 缺点
      • 存在空间浪费
    • 应用场景
      • 在新生代,常规的垃圾回收,一次可以回收大部分内存空间,剩余存活对象不多,因此现在的商业虚拟机都是用这种收集算法回收新生代

    在这里插入图片描述

  • 标记-压缩算法:标记过程仍然与“标记-清除”算法一样,之后将所有的存活对象压到内存的一端,按顺序排放,之后,清理边界外的内存

    • 优点
      • 解决了标记-清除算法出现内存碎片的问题
      • 解决了复制算法中空间浪费的问题
    • 缺点
      • 效率上低于复制算法
      • 移动对象时,如果对象被其他对象引用,则还需要调整引用的地址
      • 移动过程中,需要暂停用户应用程序。即 STW

    在这里插入图片描述

  • 分代收集算法:把 Java 堆分为新生代和老年代,这样就可以对不同生命周期的对象采取不同的收集方式,以提高回收效率

    当前商业虚拟机都采用这种算法

    • 新生代中的对象生命周期短,存活率低,因此适合使用复制算法(存活对象越少,复制算法效率越高)
    • 老年代中对象生命周期长,存活率高,回收没有新生代频繁,一般使用标记-清除或者是标记-压缩

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

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

相关文章

多示例VS多标签VS多示例多标签-week2

一、多示例 多示例学习属于弱监督学习中的一种&#xff0c;在对模型进行训练时&#xff0c;我们需要把训练数据分成正负包&#xff0c;再将每个包分成大小相同的示例&#xff0c;并且我们只对包的正负进行标注&#xff0c;而不对示例进行分类。当某个包被标识为正时&#xff0c…

Python常见面试知识总结(二):数据结构、类方法及异常处理

【十三】Python中assert的作用&#xff1f; Python中assert&#xff08;断言&#xff09;用于判断一个表达式&#xff0c;在表达式条件为 f a l s e false false的时候触发异常。 断言可以在条件不满足程序运行的情况下直接返回错误&#xff0c;而不必等待程序运行后出现崩溃…

【项目管理】如何用思维导图做计划?

思维导图是一种可视化的思维工具&#xff0c;它可以让我们的思考过程变得很直观。它可以帮助我们考虑到计划的各个方方面面&#xff0c;确定各要素之间的关系。 思维导图总结功能很强&#xff0c;完成计划后&#xff0c;可以用思维导图进行总结&#xff0c;为下一次做计划积累…

使用【ShardingSphere】分库分表

前言 ShardingSphere可以支撑分库分表&#xff0c;刚果商城采用了垂直分库&#xff08;根据不同业务拆分数据库&#xff09;&#xff0c;因此此文章只演示水平分表。 垂直分库 不同业务拆分为不同的数据库&#xff08;例如商城业务&#xff09; 水平分表 分表可以通过将大表拆…

移液器吸头材质选择——PFA吸头在半导体化工行业的应用

PFA吸头是一种高性能移液器配件&#xff0c;这种材料具有优异的耐化学品、耐热和电绝缘性能&#xff0c;使得PFA吸头在应用中表现出色。那么它有哪些特点呢&#xff1f; 首先&#xff0c;PFA吸头具有卓越的耐化学腐蚀性能。无论是酸性溶液、碱性溶液还是有机溶剂&#xff0c;P…

如何用CHAT帮你提高工作效率?

问CHAT&#xff1a;从规范项目管理流程交付&#xff0c;分别对项目信息安全管理&#xff0c;项目预算管理和项目采购管理三个方面提建议 CHAT回复&#xff1a; 项目信息安全管理: 1. 制定详细的信息安全政策&#xff0c;所有参与项目的员工必须遵守&#xff0c;对其中涉及敏感…

wpf TelerikUI使用DragDropManager

首先&#xff0c;我先创建事务对象ApplicationInfo&#xff0c;当暴露出一对属性当例子集合对于构成ListBoxes。这个类在例子中显示如下代码&#xff1a; public class ApplicationInfo { public Double Price { get; set; } public String IconPath { get; set; } public …

亚马逊S3V4验签与MINIO验签区别

1、先看下官方文档 AWS S3V4 DEMO 2、实际调用试试 1&#xff09;代码 // 计算auth// for a simple GET, we have no body so supply the precomputed empty hashMap<String, String> headers new HashMap<String, String>();headers.put("x-amz-content…

0013Java安卓程序设计-ssm酒品移动电商平台app

文章目录 **摘要**目录系统实现5.1 APP端5.2管理员功能模块开发环境 编程技术交流、源码分享、模板分享、网课分享 企鹅&#x1f427;裙&#xff1a;776871563 摘要 首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析…

Firewalld 防火墙配置

文章目录 Firewalld 防火墙配置1. Firewalld 概述2. 区域名称及策略规则3. Firewalld 配置方法4. Firewalld 参数和命令5. Firewalld 两种模式6. Firewalld 使用 Firewalld 防火墙配置 1. Firewalld 概述 firewalld 是一个动态防火墙管理器&#xff0c;作为 Systemd 管理的防…

【docker】常用命令

启动docker服务 systemctl start docker 停止docker服务 systemctl stop docker 重启docker服务 systemctl restart docker 查看docker服务状态 systemctl status docker 设置开机启动docker服务 systemctl enable docker 设置关闭开机启动docker服务 systemctl disable …

数据在内存中的存储(浮点型篇)

1.例子&#xff1a;5.5&#xff1a;内存存储为101.1&#xff0c;十分位百分位依次为2的-1次方&#xff0c;2的-2次方&#xff0c;而使用科学计数法可以改写为1.011*2的2次方 2.国际标准公式&#xff1a;-1的D次方*M*2的E次方&#xff0c;x1负0正 3.M在存储时默认整数部分为1&…

springcloud微服务篇--1.认识微服务

一、服务架构演变。 单体架构&#xff1a; 将业务的所有功能集中在一个项目中开发&#xff0c;打成一个包部署。 优点&#xff1a;架构简单 &#xff0c;部署成本低。 缺点&#xff1a;耦合度高 分布式架构 根据业务功能对系统进行拆分&#xff0c;每个业务模块作为独立项…

[idea]idea连接clickhouse23.6.2.18

一、安装驱动 直接在pom.xml加上那个lz4也是必要的不然会报错 <dependency><groupId>com.clickhouse</groupId><artifactId>clickhouse-jdbc</artifactId><version>0.4.2</version></dependency><dependency><group…

【51单片机系列】使用74HC595控制数码管显示

使用74HC595结合数码管显示字符。 proteus仿真设计如下&#xff0c;74HC595的输出端连接到动态数码管的位选和静态数码管的段选&#xff0c;动态数码管的段选连接到P0口。这两个数码管都是共阴极的。 静态数码管显示字符0-F&#xff0c;软件设计如下&#xff1a; /*实现功能&a…

【hcie-cloud】【8】华为云Stack_LLD设计【部署设计、资源设计、服务设计、学习推荐、缩略语】【下】

设计概览、整体架构设计、网络设计 看下面-这篇文章 【hcie-cloud】【7】华为云Stack_LLD设计【设计概览、整体架构设计、网络设计、部署设计、资源设计、服务设计】【上】 部署设计 云平台整体部署架构 图中在Region下每个灰底都代表一个数据中心&#xff0c;AZ1可以跨数据…

yarn系统架构与安装

1.1 YARN系统架构 YARN的基本思想是将资源管理和作业调度/监视功能划分为单独的守护进程。其思想是拥有一个全局ResourceManager (RM)&#xff0c;以及每个应用程序拥有一个ApplicationMaster (AM)。应用程序可以是单个作业&#xff0c;也可以是一组作业。 一个ResourceManage…

【信息安全】-ISO/IEC 27001-2022(翻译)

文章目录 范围规范性引用文件3 术语和定义4 组织环境&#xff08;P&#xff09;4.1 理解组织及其环境4.2 理解相关方的需求和期望组织应确定:a) 信息安全管理体系相关方;b) 这些相关方的相关要求;c) 哪些要求可以通过信息安全管理体系得到解决。注:相关方的要求可包括法律、法规…

kuboard如何部署nacos?

​ kuboard如何部署nacos&#xff1f; 这个快速开始手册是帮忙您快速在您的电脑上&#xff0c;下载、安装并使用 Nacos。 项目包含一个可构建的Nacos Docker Image&#xff0c;旨在利用StatefulSets在Kubernetes上部署Nacos。 在高级使用中,Nacos在K8S拥有自动扩容缩容和数据…