JVM基础(4)——JVM存活判定算法

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析

阶段4、深入jdk其余源码解析

阶段5、深入jvm源码解析

一、简介

我们在 JVM垃圾回收机制一章中,简单介绍了JVM的垃圾回收机制,先来回顾下,系统运行时创建的对象优先在Java堆内存区域分配:

然后新生代里的对象越来越多,当快满了的时候就会触发“Minor GC”,把新生代中的一些对象回收掉:

那么这里就涉及一个问题: JVM如何知道要去回收哪些对象? 这其实就是JVM的对象存活判定机制,主要涉及两种算: 可行性分析算法 和 引用计数算法 。

引用计数算法,是给对象添加一个引用计数器,每当有一个地方引用它时,计数器就加1,当引用失效时,计数器值就减1,任何时刻计数器为0的对象就是可以被回收的。

由于Java语言没有选用引用计数法来管理JVM内存,所以本文不赘述,而且引用计数法不能很好的解决循环引用的问题(Python采用的是引用计数法)。

二、可达性分析算法

可达性分析算法(GC Root Tracing ),其基本思路就是通过一系列的名为" GC Roots "的对象作为起始点,从这些起始点开始搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时(即从 GC Roots 到这个对象不可达),则证明此对象是不可用的,就可以被回收。

GC Roots包括:

  • Java虚拟机栈中的局部变量(指向着GC堆里的对象);
  • VM的一些静态数据结构里指向GC堆里的对象的引用,例如HotSpot VM里的Universe里有很多这样的引用;
  • 所有当前被加载的Java类(看情况);
  • Java类的运行时常量池里的引用类型常量;
  • String常量池(StringTable)里的引用。

可达性分析算法最难理解的就是该选取哪些对象作为GC Roots,我们通过两个示例来看下。

2.1 示例一

下面是最常见的一种情况:

    public class Kafka {public static void main(String[] args) {loadReplicasFromDisk();}public static void loadReplicasFromDisk(){ReplicaManager replicaManager = new ReplicaManager();}}

当执行到loadReplicasFromDisk()时,对应的JVM内存数据结构如下图:

假如此时新生代的内存已经快满了,发生了“Minor GC”,那么JVM会分析ReplicaManager对象的可达性,发现它被“replicaManager”这个局部变量引用着,在JVM规范中, 局部变量是可以作为GC Roots的 ,所以就不会被回收。

2.2 示例二

另一种比较常见的情况,是下面这种样子:

    public class Kafka {public static ReplicaManager replicaManager = new ReplicaManager();}

对应的JVM内存数据结构如下图:

假如此时新生代的内存已经快满了,发生了“Minor GC”,那么JVM会分析ReplicaManager对象的可达性,发现它被“replicaManager”这个方法区中的静态变量引用着,在JVM规范中, 静态变量是可以作为GC Roots的 ,所以就不会被回收。

三、Java引用类型

可达性分析与Java的引用类型有关联,为了更好的管理对象的内存,更好的进行垃圾回收,JVM团队扩展了引用类型,从最早的强引用类型增加到 强引用 、 软引用 、 弱引用 、 虚引用 四个引用类型:

3.1 强引用(StrongReference)

默认的对象都是强引用类型,如果JVM在对象存活判定时,通过GC Roots可达性分析结果为可达,表示引用类型仍然被引用着,这类对象始终不会被垃圾回收器回收。比如下面这段代码:

    public class Kafka {public static ReplicaManager replicaManager = new ReplicaManager();}

3.2 软引用(SoftReference)

在JVM内存充足的情况下,软引用是不会被GC回收的, 只有在JVM内存不足的情况下,才会被GC回收 。比如下面这段代码:

    public class Kafka {public static SoftReference<ReplicaManager> replicaManager = new SoftReference<ReplicaManager>(new ReplicaManager());}

适用场景: 网页缓存、图片缓存

3.3 弱引用(WeakReference)

不论当前JVM内存是否充足,都 只能存活到下一次垃圾收集之前 ,说的直白点,只要发生GC弱引用对象就会被回收,比如下面这段代码:

    public class Kafka {public static WeakReference<ReplicaManager> replicaManager = new WeakReference<ReplicaManager>(new ReplicaManager());}

ThreadlLocal中定义的ThreadLocalMap就使用到的弱引用。ThreadLocalMap的Entry,其Key就是一个弱引用对象,读者可以参考我的《Java多线程系列》。

3.4 虚引用(PhantomReference)

虚引用,不会影响对象的生命周期,所持有的引用就跟没持有一样,随时都能被GC回收。在使用虚引用时,必须和 引用队列 关联使用。其使用场景是用来跟踪对象被垃圾回收器回收的活动。

在对象的垃圾回收过程中,如果GC发现一个对象还存在虚引用,则会把这个 虚引用加入到与之关联的引用队列 中。

程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象内存被回收之前采取必要的行动防止被回收。

四、finalize方法

大家理解完了GC Roots和引用类型的概念,基本就都知道了哪些对象可以被回收,哪些对象不可以被回收:

有GC Roots引用的对象不能回收,没有GC Roots引用的对象,如果是软引用或弱引用,可能会被回收。

真正的回收环节,待被回收的对象其实还有一次机会拯救自己,那就是对象的finalize()方法。我们通过一段代码示例来看下:

    public class ReplicaManager {public static ReplicaManager instance;@Overrideprotected void finalize() throws Throwable {ReplicaManager.instance = this;}}

假如有一个ReplicaManager对象马上就要被回收了(此时已经没有GC Roots到达它的链路),此时GC会首先调用下该对象的finalize()方法,看看它是否找了一个新的GC Roots来引用自己,比如上述代码中,GC发现有个静态变量instance引用了该实例,那GC就不会去回收它。

finalize方法没事不要去重写,这都是GC内部的机制,平时也几乎不用。

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

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

相关文章

【C#】使用 LINQ 中的 Skip() 和 Take()进行分页,为什么要分页,分页作用是什么

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是是《C#》序列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握…

自己在家怎么给电脑重装系统不用U盘?

自己在家怎么给电脑重装系统不用U盘&#xff1f;用户发现自己在家用的电脑系统出现很严重的问题&#xff0c;但又没有U盘&#xff0c;想知道有什么方法能够给电脑重新安装上一款正常的系统&#xff1f;接下来小编给用户们分享不用U盘完成系统重新安装的方法步骤&#xff0c;一键…

【HTML】对字体的所有操作详解(经典)

目录 一、文字样式设置的基本标签二 、 设置文字的颜色三、设置文字的尺寸四、 设置文字的字体五、 使文字倾斜六、 使文字加粗七、处理网页中的特殊字符十、 如何更方便地忽略浏览器对部分HTML的解析十一、 其他文字修饰方法十二、为了让文字富有变化&#xff0c;或者为了着意…

异步编程利器:CompletableFuture深度解析

本文已收录至Github&#xff0c;推荐阅读 &#x1f449; Java随想录 微信公众号&#xff1a;Java随想录 文章目录 摘要如何使用源码解析基本结构内部原理执行流程 方法介绍创建对象异步执行任务链式操作异步任务组合异常处理取值与状态超时控制与取消操作依赖完成并发限制记忆…

66、python - 代码仓库介绍

上一节,我们可以用自己手写的算法以及手动搭建的神经网络完成预测了,不知各位同学有没有自己尝试来预测一只猫或者一只狗,看看准确度如何? 本节应一位同学的建议,来介绍下 python 代码仓库的目录结构,以及每一部分是做什么? 我们这个小课的代码实战仓库链接为:cv_lea…

Python 面向对象之单例模式

【一】单例模式概念 单例模式是一种设计模式&#xff0c;其核心思想是确保一个类只有一个实例&#xff0c;并提供一个全局访问点。单例模式通常用于管理共享的资源&#xff0c;例如配置信息、数据库连接、线程池等。关键点在于如何判断这个类是否已经实例化 通过模块导入&…

Codeforces Round 911 C. Anji‘s Binary Tree

原题&#xff1a; C. Anji’s Binary Tree time limit per test 2.5 seconds memory limit per test 256 megabytes input standard input output standard output Keksic keeps getting left on seen by Anji. Through a mutual friend, he’s figured out that Anji really …

人工智能行业的发展前景如何?

人工智能&#xff08;AI&#xff09;已经成为如今科技领域的热门话题之一&#xff0c;从图像识别到自动驾驶&#xff0c;从语音助手到智能机器人&#xff0c;AI技术正在改变我们的生活方式。随着技术的不断发展和应用的扩大&#xff0c;人工智能行业的发展前景无疑是非常广阔的…

[足式机器人]Part2 Dr. CAN学习笔记-Advanced控制理论 Ch04-4系统的可控性Controllability(LTI)线性时不变

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-Advanced控制理论 Ch04-4系统的可控性Controllability-LTI线性时不变

数字之美:探秘数据可视化如何在我们的日常生活中展现魅力

数据可视化是如何通过多种方式走进我们生活的呢&#xff1f;它不仅仅是冰冷的数字和图表&#xff0c;更是一门让信息跃然纸上的艺术。让我们一同探讨数据可视化如何以多种方式渗透进我们的日常生活&#xff0c;为我们呈现丰富而生动的信息画卷。下面我就以可视化从业者的角度来…

网络正常运行时间监控工具

正常运行时间是衡量系统可靠性的指标&#xff0c;表示为机器工作和可用时间的百分比。当提到 IT 网络时&#xff0c;正常运行时间是衡量网络设备、网站和其他服务的可用性的指标。网络正常运行时间通常以百分位数来衡量&#xff0c;例如“五个 9”&#xff0c;这意味着系统在 9…

Jetson nano 实时性测试,使用stress-ng 和 cyclictest

系统&#xff1a;ubuntu18.04&#xff0c;Jetpack4.3 打上了实时补丁 安装stress-ng和cyclictest sudo apt-get install stress-ng sudo apt-get install rt-tests 无负载情况的实时性 让两个CPU满载运行60秒 两个CPU满载实时性&#xff1a; 测了一下&#xff0c;4个CPU满载的…