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 堆分为新生代和老年代,这样就可以对不同生命周期的对象采取不同的收集方式,以提高回收效率

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

决策报表布局方式(新建一个绝对布局,双击,在拖其它图表,报表块装进去。就不会变形)

FineReport11.0 1.绝对布局&#xff1a; 只是适合自己调试电脑显示&#xff0c;适用于一个展示区域需要用多个组件叠加组成时使用 2.自适应布局&#xff1a;双向自适应 &#xff1a; https://help.fanruan.com/finereport/doc-view-4276.html 组件会自动调整显示宽度以适应不…

实战React18和TS+Vite,跟进实战阅读类App的心得分享

随着 React 18 的发布&#xff0c;以及 TypeScript 和 Vite 在前端开发领域的普及&#xff0c;使用 React 18 结合 TypeScript 和 Vite 开发实战阅读类 App 的经验已经成为了前端开发者们的热门话题。在本文中&#xff0c;我将分享我的心得体会&#xff0c;并给出一些示例代码&…

12.11_黑马数据结构与算法笔记Java

目录 070 栈 链表实现 概念理清&#xff1a;什么时候是指针的指向&#xff0c;什么时候是元素本身&#xff1f; 071 栈 数组实现 072 栈 e01 有效的括号 072 栈 e02 后缀表达式求值 072 栈 e03 中缀表达式转后缀1 072 栈 e03 中缀表达式转后缀2 072 栈 e03 中缀表达式转…

Linux之进程(三)(环境变量)

目录 一、基本概念 二、环境变量 1、PATH 2、HOME 3、SHELL 三、环境变量参数 四、argc和argv 一、基本概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。如&#xff1a;临时文件夹位置和系统文件夹位置等。环境变量通常…

通用的AGI 安全风险

传统安全风险 平台基础设施安全风险 模型与数据层安全风险 应用层安全风险 平台基础设施安全风险 &#xff08;1&#xff09;物理攻击&#xff1a;机房管控不到位 &#xff08;2&#xff09;网络攻击 &#xff08;3&#xff09;计算环境&#xff1a;自身安全漏洞&#xf…

Java - Mybatis的缓存机制、集成SpringBoot后缓存相关问题

mybaits提供一级缓存&#xff0c;和二级缓存 一级缓存&#xff08;默认开启&#xff09; 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象&#xff0c;在对象中有一个(内存区域)数据结构&#xff08;HashMap&#xff09;用于存储缓存数据。不同的sqlSe…

【Java SE】带你识别什么叫做异常!!!

&#x1f339;&#x1f339;&#x1f339;个人主页&#x1f339;&#x1f339;&#x1f339; 【&#x1f339;&#x1f339;&#x1f339;Java SE 专栏&#x1f339;&#x1f339;&#x1f339;】 &#x1f339;&#x1f339;&#x1f339;上一篇文章&#xff1a;【Java SE】带…

U5 符号表管理

文章目录 一、语义分析1、任务 二、符号表1、概述2、操作3、基本结构4、组织方式 三、非分程序的符号表1、概念2、标识符的作用域及基本处理办法3、符号表的组织方式 四、分程序的符号表&#xff1a;处理作用域嵌套1、概念2、处理方法 五、栈式符号表六、基于符号表的存储组织与…

Appilied energy论文复现:计及光伏电站快速无功响应特性的分布式电源优化配置方法程序代码!

本程序参考Applied energy论文《Optimal siting and sizing of distributed generation in distribution systems with PV solar farm utilized as STATCOM (PV-STATCOM)》&#xff0c;文中主要对光伏电站、微燃机等分布式电源进行优化配置&#xff0c;程序较为简单和基础&…

SD生成的图像不清晰,如何解决

文生图 选择高清修复&#xff1a; 几点注意 重绘幅度&#xff1a;这里不用太高&#xff0c;他会根据你生成的低分辨率图像&#xff0c;生成高分辨率的图像&#xff0c;可以选择0.3~05之间&#xff0c;给AI跟多想象力空间可以选择0.5 ~ 0.7。太低边缘模糊&#xff0c;太高了可能…

《数字图像处理-OpenCV/Python》连载(56)图像的灰度直方图

《数字图像处理-OpenCV/Python》连载&#xff08;56&#xff09;非线性灰度变换 本书京东 优惠购书链接 https://item.jd.com/14098452.html 本书CSDN 独家连载专栏 https://blog.csdn.net/youcans/category_12418787.html 第 8 章 图像的直方图处理 图像的直方图是反映像素值…

约瑟夫问题

目录 方法一&#xff1a;数组模拟 方法二&#xff1a;链表模拟 方法三&#xff1a;数学递归 约瑟夫问题&#xff1a; 编号为 1 到 n 的 n 个人围成一圈。从编号为 1 的人开始报数&#xff0c;报到 m 的人离开。下一个人继续从 1 开始报数。 n-1 轮结束以后&#xff0c;只剩下…

人人都能用的AI编程助手 CodeGeeX

视频版&#xff1a;人人都能用的Ai编程助手——CodeGeeX 大家好&#xff0c;我是凌览。 现在距离 AI 大火已经快有一年啦&#xff0c;作为程序员可不得准备一款AI帮咱们干点活。本文分享一款 AI 工具 CodeGeeX&#xff0c;帮助大家提高一波学习和工作效率。 CodeGeeX 是什么…

Linux之Apache服务器安装及配置

一、Apache服务器简介 Apache HTTP Server&#xff08;简称Apache&#xff09;是Apache软件基金会的一个开放源码的网页服务器&#xff0c;可以在大多数计算机操作系统中运行&#xff0c;由于其多平台和安全性被广泛使用。Apache曾经是世界使用排名第一的Web服务器软件&#xf…

strict-origin-when-cross-origin

严格限制同源策略 &#xff08;1&#xff09;允许服务器的同源IP地址访问 &#xff08;2&#xff09;允许Referer --- 后端服务器要配置

两线制 4-20mA 隔离变送器(输出回路供电)

两线制 4-20mA 隔离变送器(输出回路供电) 特征&#xff1a; ◆低成本&#xff0c;小体积&#xff0c;符合 UL94-V0 阻燃标准 ◆安装方式采用国际标准 DIN35mm 导轨安装方式 ◆双隔离(信号输入、信号输出相互之间 3000VDC 隔离) ◆4-20mA 电流输入与输出&#xff0c;精度高(失真…

ansible部署安装Tomcat

我们需要用到的文件jdk以及tomcat安装包 下载链接:https://pan.baidu.com/s/1sjG8Yl8k-SUbOv7KwKXZMA 提取码&#xff1a;t71z 准备n台机器&#xff08;我这里就简单部署三台机器&#xff09; ansible的安装部署以及配置可以看博主之前的文章自动化运维工具-ansible部署 ansib…

zookeeper高级应用原理

文章目录 分布式锁分布式锁-读写锁分布式锁-Curator实现ZK集群管理 zookeeper 集群zookeeper 集群节点个数配置zookeeper 选举ZAB协议zookeeper 选举zookeeper 集群数据读写 分布式锁 分布式锁&#xff1a;在分布式环境下&#xff0c;保护跨进程、跨主机、跨网络的共享资源&am…

Day57力扣打卡

打卡记录 最小体力消耗路径 链接 Dijkstra 将Dijkstra算法从计算最短路径转化为计算路径最大差值。 class Solution:def minimumEffortPath(self, heights: List[List[int]]) -> int:n, m len(heights), len(heights[0])dist [0] [0x3f3f3f3f] * (n * m - 1)vis set…

iPhone 数据恢复:iMyFone D-Back iOS

iMyFone D-Back iOS 最佳 iPhone 数据恢复&#xff0c;最好的 iPhone 数据恢复软件&#xff0c;恢复成功率最高。 直接从iOS设备、iTunes/iCloud/第三方程序备份快速恢复数据。 有选择地恢复已删除的照片、WhatsApp、消息和 18 多种其他数据类型。 仅通过 iCloud 帐户访问即可从…