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

news2025/1/26 14:17:19

作者简介:大家好,我是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;
    
        @Override
        protected void finalize() throws Throwable {
            ReplicaManager.instance = this;
        }
    }

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

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

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

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

相关文章

ArcGIS Pro中怎么加载在线地图

当我们在制图的时候&#xff0c;有的时候需要加载在线地图&#xff0c;在ArcGIS Pro中加载在线地图的方式有很多&#xff0c;这里为大家介绍一下加载的方法&#xff0c;希望能对你有所帮助。 加载底图 在菜单栏上选择地图&#xff0c;点击底图&#xff0c;可以看到所有可加载…

记录下载安装rabbitmq(Linux) 并整合springboot--详细版(全)

下载rabbitmq&#xff08;Linux&#xff09;&#xff1a; erlang压缩包&#xff1a; https://share.weiyun.com/TGhfV8eZ rabbitMq-server压缩包&#xff1a; https://share.weiyun.com/ZXbUwWHD &#xff08;因为RabbitMQ采用 Erlang 实现的工业级的消息队列(MQ)服务器&#…

【Nuxt3】Nuxt3脚手架nuxi安装项目和项目目录介绍

简言 最近学了Nuxt3,并使用它创建了自己的小网站。记录下学习到的nuxt3内容。 Nuxt3官网 Nuxt 是一个免费的开源框架&#xff0c;可通过直观、可扩展的方式使用 Vue.js 创建类型安全、高性能、生产级的全栈 Web 应用程序和网站。 支持SSR、SPA、建立静态网站&#xff0c;也可以…

C++ 图形界面学习效果及代码

#include <stdio.h> #include<conio.h> #include <stdlib.h> #include<graphics.h> #define WIDTH 800 #define HEIGHT 480 #define SIZE 20 int main() {const char* str "人生就是由欲望不满足而痛苦和满足之后无趣这两者所构成";const …

【征服redis1】基础数据类型详解和应用案例

博客计划 &#xff0c;我们从redis开始&#xff0c;主要是因为这一块内容的重要性不亚于数据库&#xff0c;但是很多人往往对redis的问题感到陌生&#xff0c;所以我们先来研究一下。 本篇&#xff0c;我们先看一下redis的基础数据类型详解和应用案例。 1.redis概述 以mysql为…

性能测试之全链路压测正确优化思路

性能测试之全链路压测的优化需要从多个方面入手&#xff0c;包括明确压测目标、模拟真实场景、选择合适的工具和技术、合理设计压测方案、分析性能瓶颈以及持续监控和改进等。通过这些措施的实施&#xff0c;可以有效地提高系统的性能和稳定性&#xff0c;为用户提供更好的服务…

ffmpeg解码音频planar模式和packed模式

转载&#xff1a;原文地址&#xff1a; FFmpeg连载4-音频解码-阿里云开发者社区ffmpeg连载系列https://developer.aliyun.com/article/1197520 转载的&#xff0c;看到了&#xff0c;留着备份一下 导读 前面我们介绍了使用FFmpeg解码视频&#xff0c;今天我们使用FFmpeg解码音…

MySQL的多表数据记录查询笔记

关系数据操作 合并查询数据记录 在MySQL中通过关键字UNION来实现并操作&#xff0c;即可以通过其将多个SELECT语句的查询结果合并在一起组成新的关系。 两张表&#xff0c;表1 和表2 带有关键字UNION的合并操作 关键字UNION会把查询结果集直接合并在一起&#xff0c;同时将…

现代控制理论基础

在学习卡尔曼滤波、粒子滤波、隐马尔可夫模型时候&#xff0c;经常会提到状态方程的概念&#xff0c;这边联想到当时学习过的一门课程现代控制理论&#xff0c;这边就简单回顾一下吧。在回顾之前&#xff0c;串联下高等数学中微分方程的知识点。 一. 微分方程 高等数学上册第…

今年的年终奖开了个寂寞

大家好啊&#xff0c;我是董董灿。 年底了&#xff0c;又到了一些公司开年终奖的时候了&#xff0c;往年这个时候&#xff0c;网上都是争相"炫富"的声音。 还记得去年某公司&#xff0c;在春节前一下子开出了十几个月的年终奖&#xff0c;让我羡慕了好长时间。 可…

JAVAEE——request对象(三)

1. request对象 1.1 知识点 &#xff08;1&#xff09;乱码问题的两种解决方式 &#xff08;2&#xff09;post和get提交的区别 &#xff08;3&#xff09;request接收同名参数的问题 1.2 具体内容 使用request接收参数 <%page contentType"text/html; charsetut…

深入理解 go chan

go 里面&#xff0c;在实际程序运行的过程中&#xff0c;往往会有很多协程在执行&#xff0c;通过启动多个协程的方式&#xff0c;我们可以更高效地利用系统资源。 而不同协程之间往往需要进行通信&#xff0c;不同于以往多线程程序的那种通信方式&#xff0c;在 go 里面是通过…

C++ Primer 6.3 返回类型和return语句 知识点+练习题

C Primer 6.3 返回类型和return语句 无返回值函数有返回值的函数两个错误值是如何被返回的返回类类型的函数和调用运算符引用返回左值列表初始化返回值主函数main的返回值返回数组指针 递归练习题疑问待更新 无返回值函数 用在返回值类型为void的函数中&#xff0c;可以不写re…

01章【JAVA开发入门】

计算机基本概念 计算机组成原理 计算机组装 计算机&#xff1a;电子计算机&#xff0c;俗称电脑。是一种能够按照程序运行&#xff0c;自动、高速处理海量数据的现代化智能电子设备。由硬件和软件所组成&#xff0c;没有安装任何软件的计算机称为裸机。常见的形式有台式计算机、…

浅析五种 React 组件设计模式

作为一名 React 开发者&#xff0c;你可能会面临下面几个问题&#xff1a; 如何构建一个高复用度性的组件&#xff0c;使其适应不同的业务场景&#xff1f;如何构建一个具有简单 API的组件&#xff0c;使其易于使用&#xff1f;如何构建一个在 UI 和功能方面具有可扩展性的组件…

Vue3-TS中的接口-泛型-自定义类型

1首先一般在src下新建types文件夹&#xff0c;用来存放接口类型 2定义一个接口&#xff0c;用于限制person对象的具体属性 当需要用这个类型形成数组时&#xff0c;有2种写法 export type Persons Array<PersonInter> export type Persons PersonInter[] 3在文件中使…

检索增强生成技术(RAG)深度优化指南:原理、挑战、措施、展望

ChatGPT、Midjourney等生成式人工智能&#xff08;GenAI&#xff09;在文本生成、文本到图像生成等任务中表现出令人印象深刻的性能。然而&#xff0c;生成模型也不能避免其固有的局限性&#xff0c;包括产生幻觉的倾向&#xff0c;在数学能力弱&#xff0c;而且缺乏可解释性。…

C++基础算法之贪心

临渊羡鱼 不如退而结网 &#x1f3a5;烟雨长虹&#xff0c;孤鹜齐飞的个人主页 &#x1f525;个人专栏 寒假带大家手撕算法 期待小伙伴们的支持与关注&#xff01;&#xff01;&#xff01; 目录 贪心算法的简介 贪心算法的介绍# 贪心的基本原理# 贪心的局限性# 贪心的特征# 贪…

用julia演示蝴蝶效应:洛伦兹吸引子

文章目录 Lorentz吸引子julia绘图关闭抗锯齿 蝴蝶效应的名字来源于蝴蝶扇动翅膀的动作&#xff0c;虽然这个动作微小&#xff0c;但可能会在数周后引起飓风等极端天气的发生。这种现象表明&#xff0c;微小的变化可能会被放大并产生非线性的结果。这个概念最早由美国气象学家爱…