【从零开始学习JVM | 第七篇】深入了解 堆回收

news2024/11/13 11:22:34

前言:

       Java堆作为内存管理中最核心的一部分,承担着对象实例的存储和管理任务。堆内存的高效使用对于保障程序的性能和稳定性至关重要。因此,深入理解Java堆回收的原理、机制和优化策略,对于Java开发人员具有重要的意义。

本文旨在探讨Java堆回收的相关概念、工作原理以及常见的回收算法,帮助读者全面理解Java内存管理中的关键环节,并提供实用的建议和最佳实践,以便更好地应对内存管理方面的挑战,提升Java应用程序的性能和稳定性。

目录

前言:

堆回收的常见判断方法:

1.引用计数法:

2.可达性分析法:

可达性分析法: 

常见的GC Root对象:

JAVA的四种引用关系:

1.强引用:

2.软引用:

3.弱引用: 

4.虚引用: 

总结:


堆回收的常见判断方法:

1.引用计数法:

        每个对象维护一个引用计数器,记录被其他对象引用的次数。当计数器为0时,表示该对象不再被引用,可以被回收。然而,引用计数法难以解决循环引用的问题,即若存在循环引用,即使对象互相不可达,其引用计数也不为0,导致无法回收。

2.可达性分析法:

        通过一组称为"GC Roots"的根对象作为起点,从这些根对象出发,沿着引用链进行遍历,标记所有被引用的对象为可达对象。剩下的未被标记的对象即为不可达对象,可以被回收。在Java中,根对象包括虚拟机栈中引用的对象、方法区中静态变量引用的对象以及本地方法栈中JNI(Java Native Interface)引用的对象。

在这种对象区分中,根对象和普通对象是存在引用关系的

可达性分析算法是指:如果从某个对象到 GC Root对象是可达的,对象就不可以被回收。

简单的来说:我们利用 根对象 将 所有  需要判定是否回收 的对象分为了两类:根对象可达的对象根对象不可达的对象根对象可达的 对象 不可以 回收,根对象不可达的对象 可以进行回收

而Java进行堆回收的时候,使用的方法就是:可达性分析法,因此我们来深入学习一下可达性分析法:

可达性分析法: 

由上文我们简单的介绍可达性分析算法中,可以看出学习JVM中哪些对象是GC Root对象是比较重要的:

常见的GC Root对象:

  • 线程Thread对象。
  • 系统类加载器加载的Java.long.Class对象。
  • 监视器对象,用于保存同步锁synchronized 关键字所持有的对象。
  • 本地方法调用时使用的全局对象。 

 如何判断一个对象是否被GC Root对象引用:

  1. 使用工具:可以使用 Java 调试工具,如 jmap、jconsole、jvisualvm 等,来查看堆中的对象引用关系。这些工具可以提供实时的内存快照,并显示对象的引用链。如果发现某个类的引用链中没有 GC Root 对象,那么该类就不是 GC Root 对象。

  2. 分析代码:通过代码分析,可以判断一个类是否是 GC Root 对象。通常情况下,以下几种情况会使一个类成为 GC Root 对象:

    • 作为线程对象的局部变量或静态变量。
    • 作为系统类加载器加载的 Class 对象的局部变量或静态变量。
    • 作为锁对象进行同步操作。
    • 作为本地方法调用时使用的全局对象。

    可以检查代码中是否存在上述情况,如果不存在,则说明该类不是 GC Root 对象。

但是不是只有满足上述条件的对象,才会被回收呢?

其实并不是的,通过GC Root引用对象只是 Java的五种对象引用的一种,我们来学习一下 这五种对象引用,以及在这五种引用下是如何判断对象能否回收的。

JAVA的四种引用关系:

1.强引用:

        使用最常见的引用方式。当一个对象被强引用关联时,即使内存不足时也不会被垃圾回收器回收。只有当该对象没有任何强引用时,才可能被回收

可达性分析算法中描述的对象引用一般就是强引用。

Java 中 大部分场景 都用的是 强引用 :

  1. 对象的直接引用:当使用类似 Object obj = new Object(); 这样的语句时,obj 对象就是一个强引用,因为它明确指向了一个对象。

  2. 静态变量:静态变量通常存放在方法区中,在类加载的过程中初始化,其生命周期和类一样长,因此静态变量的引用是强引用。

  3. 实例变量:对象中的实例变量也具有强引用,只要对象存在,其实例变量的引用就会一直存在。

2.软引用:

        使用SoftReference类表示,通过SoftReference包装一个对象。当内存不足时,垃圾回收器可能会回收被软引用关联的对象,但这不是强制性的,只有当内存真正不足时才会回收

 软引用 常用在 缓存 当中。不会用软引用来关联代码中的核心类,因为核心类不应该被回收。

软引用的应用场景: 

缓存和高速缓存:软引用可以用于实现缓存或高速缓存,当内存不足时,垃圾回收器可能会回收已经被软引用关联的对象。这种方式可以避免内存溢出的问题。例如:

Map<Key, SoftReference<Value>> cache = new HashMap<>();
Value getValue(Key key) {
    SoftReference<Value> ref = cache.get(key);
    if (ref != null) {
        Value value = ref.get();
        if (value != null) {
            return value;
        }
    }
    Value value = ...; // 从文件、数据库等获取
    cache.put(key, new SoftReference<>(value));
    return value;
}

对象池:对象池可以使用软引用来实现对象的复用,当内存不足时,垃圾回收器可能会回收已经被软引用关联的对象。这种方式可以避免创建过多的对象,提高系统性能。例如:

class ObjectPool<T> {
    private final List<SoftReference<T>> pool = new ArrayList<>();
    private final Supplier<T> supplier;
    ObjectPool(Supplier<T> supplier) {
        this.supplier = supplier;
    }
    T acquire() {
        for (int i = 0; i < pool.size(); i++) {
            SoftReference<T> ref = pool.get(i);
            T object = ref.get();
            if (object != null) {
                pool.remove(i);
                return object;
            }
        }
        T object = supplier.get();
        return object;
    }
    void release(T object) {
        pool.add(new SoftReference<>(object));
    }
}

需要注意的是,软引用不是绝对可靠的,垃圾回收器并不保证在内存不足时一定会回收被软引用关联的对象,因此在使用软引用时,需要根据具体场景进行合理的设计和配置。

软引用的使用就是:创建一个软引用对象 SoftReference 把 需要设置软引用的对象包装起来:

如图所示:我们就把一个 HashMap对象 包装在了一个软引用中,当系统的内存不足的时候,就会考虑回收这个HashMap对象。

3.弱引用: 

        使用WeakReference类表示,通过WeakReference包装一个对象。弱引用的对象在垃圾回收时,无论内存是否充足,都可能被回收

弱引用的使用场景:

ThreadLocal 是一个线程级别的变量存储工具,在多线程环境下可以实现线程间的数据隔离。每个线程都有自己独立的 ThreadLocal 变量副本,可以在不同线程中存储不同的值,而不会相互干扰。

通常情况下,ThreadLocal 的实现会使用一个 Map 来存储每个线程对应的变量副本。为了避免内存泄漏,ThreadLocal 对这些变量副本使用弱引用进行引用。

我们可以看到:当我们在构造Map用的Entry的时候,就用的是 虚引用 。 

 当一个线程结束或被回收时,对应的 ThreadLocal 弱引用会被垃圾回收器回收,进而导致对应的变量副本也会被回收。这样可以有效地释放线程相关的资源,避免内存泄漏问题。

4.虚引用: 

        使用PhantomReference类表示,通过PhantomReference包装一个对象。虚引用主要用于检测对象是否已经被垃圾回收器标记为可回收,在实际使用中很少直接操作虚引用对象。

虚引用(Phantom Reference)是Java中最弱的引用类型之一,它几乎没有实际的用途。虚引用主要用于监控对象是否被垃圾回收器回收,无法通过虚引用来获取对象的实例。

虚引用与其他引用类型不同,它的主要作用在于提供了一种在对象被垃圾回收时,能够在对象被销毁之前执行一些必要的清理操作的机制。虚引用通常会和引用队列(ReferenceQueue)一起使用。

在使用虚引用时,需要创建一个引用队列,并将虚引用对象与引用队列关联起来。当对象被垃圾回收器回收时,会将虚引用放入引用队列中,通过检查引用队列中的对象,可以得知对象已经被回收。

总结:

        本文我们首先介绍了为什么需要堆回收以及它的作用。我们了解到,Java堆是存储对象实例的地方,而垃圾对象的存在可能导致内存泄漏和性能下降。因此,堆回收是确保内存使用效率和应用程序性能的关键步骤。

其次介绍了一些与堆回收相关的重要概念,如引用类型(强引用、软引用、弱引用和虚引用)、内存分配和对象生命周期。这些概念对于理解垃圾回收机制和如何优化内存使用至关重要。

在了解到如何判断堆中的 类 是否能被回收之后,在下篇文章我们就要学习 如何 进行垃圾回收了,也就是垃圾回收算法和垃圾回收器。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

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

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

相关文章

竞赛保研 python图像检索系统设计与实现

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; python图像检索系统设计与实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 该项目较为新颖&#xff0c…

Python基础04-数据容器

零、文章目录 Python基础04-数据容器 1、了解字符串 &#xff08;1&#xff09;字符串的定义 字符串是 Python 中最常用的数据类型。我们一般使用引号来创建字符串。创建字符串很简单&#xff0c;只要为变量分配一个值即可。<class ‘str’>即为字符串类型。一对引号…

计算机毕业设计 基于SpringBoot的二手物品交易管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

【一文带你掌握Java中方法定义、调用和重载的技巧】

方法的定义和调用 方法的定义 方法&#xff08;method&#xff09;是一段用于实现特定功能的代码块&#xff0c;类似于其他编程语言中的函数&#xff08;function&#xff09;。方法被用来定义类或类的实例的行为特征和功能实现。方法是类和对象行为特征的抽象表示。方法与面向…

『PyTorch』张量和函数之gather()函数

文章目录 PyTorch中的选择函数gather()函数 参考文献 PyTorch中的选择函数 gather()函数 import torch a torch.arange(1, 16).reshape(5, 3) """ result: a [[1, 2, 3],[4, 5, 6],[7, 8, 9],[10, 11, 12],[13, 14, 15]] """# 定义两个index…

圆通速递查询,圆通速递单号查询,一键复制查询好的物流信息

批量查询圆通速递单号的物流信息&#xff0c;并将查询好的物流信息一键复制出来。 所需工具&#xff1a; 一个【快递批量查询高手】软件 圆通速递单号若干 操作步骤&#xff1a; 步骤1&#xff1a;运行【快递批量查询高手】软件&#xff0c;第一次使用的朋友记得先注册&…

002.Java实现两数相加

题意 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示两数之和的新链表。 示例 输入&#xff1a;l1[2,4,3],l2[5,6,4] 输出…

ChatGPT4 Excel 高级复杂函数案例实践

案例需求: 需求中需要判断多个条件进行操作。 可以让ChatGPT来实现这样的操作。 Prompt:有一个表格B2单元格为入职日期,C2单元格为员工等级(A,B,C),D2单元格为满意度分数(1,2,3,4,5)请给入职一年以上,员工等级为A级并且满意度在3分以上的人发4000元奖金,给入…

普冉(PUYA)单片机开发笔记(10): I2C通信-配置从机

概述 I2C 常用在某些型号的传感器和 MCU 的连接&#xff0c;速率要求不高&#xff0c;距离很短&#xff0c;使用简便。 I2C的通信基础知识请参见《基础通信协议之 IIC详细讲解 - 知乎》。 PY32F003 可以复用出一个 I2C 接口&#xff08;PA3&#xff1a;SCL&#xff0c;PA2&a…

计算机组成原理-函数调用的汇编表示(call和ret指令 访问栈帧 切换栈帧 传递参数和返回值)

文章目录 call指令和ret指令高级语言的函数调用x86汇编语言的函数调用call ret指令小结其他问题 如何访问栈帧函数调用栈在内存中的位置标记栈帧范围&#xff1a;EBP ESP寄存器访问栈帧数据&#xff1a;push pop指令访问栈帧数据&#xff1a;mov指令小结 如何切换栈帧函数返回时…

深度学习记录--矩阵维数

如何识别矩阵的维数 如下图 矩阵的行列数容易在前向和后向传播过程中弄错&#xff0c;故写这篇文章来提醒易错点 顺便起到日后查表改错的作用 本文仅作本人查询参考(摘自吴恩达深度学习笔记)

Flink系列之:SQL提示

Flink系列之&#xff1a;SQL提示 一、动态表选项二、语法三、例子四、查询提示五、句法六、加入提示七、播送八、随机散列九、随机合并十、嵌套循环十一、LOOKUP十二、进一步说明十三、故障排除十四、连接提示中的冲突案例十五、什么是查询块 SQL 提示可以与 SQL 语句一起使用来…

MyBatis Plus 大数据量查询优化

大数据量操作的场景大致如下&#xff1a; 数据迁移 数据导出 批量处理数据 在实际工作中当指定查询数据过大时&#xff0c;我们一般使用分页查询的方式一页一页的将数据放到内存处理。但有些情况不需要分页的方式查询数据或分很大一页查询数据时&#xff0c;如果一下子将数…

【单元测试】Junit 4--junit4 内置Rule

1.0 Rules ​ Rules允许非常灵活地添加或重新定义一个测试类中每个测试方法的行为。测试人员可以重复使用或扩展下面提供的Rules之一&#xff0c;或编写自己的Rules。 1.1 TestName ​ TestName Rule使当前的测试名称在测试方法中可用。用于在测试执行过程中获取测试方法名称…

MATLAB 计算两片点云间的最小距离(2种方法) (39)

MATLAB 计算两片点云间的最小距离 (39) 一、算法介绍二、算法实现1.常规计算方法2.基于KD树的快速计算一、算法介绍 假设我们现在有两片点云 1 和 2 ,需要计算二者之间的最小距离,这里提供两种计算方法,分别是常规计算和基于KD树近邻搜索的快速计算方法,使用的测试数据如…

Java 分布式框架 —— Dubbo 快速入门

1 分布式系统中的相关概念 1.1 大型互联网项目架构目标 传统项目和互联网项目 传统项目&#xff1a;例如 OA、HR、CRM 等&#xff0c;服务对象为&#xff1a;企业员工 互联网项目&#xff1a;天猫、微信、百度等&#xff0c;服务对象为&#xff1a;全体网民 互联网项目特点…

2 使用postman进行接口测试

上一篇&#xff1a;1 接口测试介绍-CSDN博客 拿到开发提供的接口文档后&#xff0c;结合需求文档开始做接口测试用例设计&#xff0c;下面用最常见也最简单的注册功能介绍整个流程。 说明&#xff1a;以演示接口测试流程为主&#xff0c;不对演示功能做详细的测试&#xff0c;…

JVM学习之JVM概述

JVM的整体结构 Hotspot VM是目前市面上高性能虚拟机代表作之一 它采用解释器与即时编译器并存的架构 在今天&#xff0c;Java程序的运行性能已经达到了可以和C/C程序一较高下的地步 Java代码执行流程 具体图为 JVM架构模型 Java编译器输入的指令流基本上是一种基于 栈的指令…

drf入门规范

一 Web应用模式 在开发Web应用中&#xff0c;有两种应用模式&#xff1a; 1.1 前后端不分离 1.2 前后端分离 二 API接口 为了在团队内部形成共识、防止个人习惯差异引起的混乱&#xff0c;我们需要找到一种大家都觉得很好的接口实现规范&#xff0c;而且这种规范能够让后端写…

【MySQL内置函数】

目录&#xff1a; 前言一、日期函数获取日期获取时间获取时间戳在日期上增加时间在日期上减去时间计算两个日期相差多少天当前时间案例&#xff1a;留言板 二、字符串函数查看字符串字符集字符串连接查找字符串大小写转换子串提取字符串长度字符串替换字符串比较消除左右空格案…