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

前言:

       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.mzph.cn/news/226755.shtml

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

相关文章

C++相关闲碎记录(16)

1、正则表达式 &#xff08;1&#xff09;regex的匹配和查找接口 #include <regex> #include <iostream> using namespace std;void out (bool b) {cout << ( b ? "found" : "not found") << endl; }int main() {// find XML/H…

ProroBuf C++笔记

一.什么是protobuf Protocol Buffers是Google的⼀种语⾔⽆关、平台⽆关、可扩展的序列化结构数据的⽅法&#xff0c;它可⽤于&#xff08;数据&#xff09;通信协议、数据存储等。Protocol Buffers 类⽐于XML&#xff0c;是⼀种灵活&#xff0c;⾼效&#xff0c;⾃动化机制的结…

SpringData自定义操作

一、JPQL和SQL 查询 package com.kuang.repositories;import com.kuang.pojo.Customer; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.PagingAndSortingR…

javaEE -17(13000字 CSS3 入门级教程)

一&#xff1a;CSS3 简介 CSS3 是 CSS2 的升级版本&#xff0c;它在 CSS2 的基础上&#xff0c;新增了很多强大的新功能&#xff0c;从而解决一些实际面临的问题&#xff0c;CSS3 在未来会按照模块化的方式去发展&#xff1a;https://www.w3.org/Style/CSS/current-work.html …

Guardrails for Amazon Bedrock 基于具体使用案例与负责任 AI 政策实现定制式安全保障(预览版)

作为负责任的人工智能&#xff08;AI&#xff09;战略的一部分&#xff0c;您现在可以使用 Guardrails for Amazon Bedrock&#xff08;预览版&#xff09;&#xff0c;实施专为您的用例和负责任的人工智能政策而定制的保障措施&#xff0c;以此促进用户与生成式人工智能应用程…

智能优化算法应用:基于哈里斯鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于哈里斯鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于哈里斯鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.哈里斯鹰算法4.实验参数设定5.算法结果6.…

linux性能优化-上下文切换

如何理解上下文切换 Linux 是一个多任务操作系统&#xff0c;它支持远大于 CPU 数量的任务同时运行&#xff0c;这是通过频繁的上下文切换、将CPU轮流分配给不同任务从而实现的。 CPU 上下文切换&#xff0c;就是先把前一个任务的 CPU 上下文&#xff08;CPU 寄存器和程序计数…

JVM学习之JVM概述

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

Transformer的学习

文章目录 Transformer1.了解Seq2Seq任务2.Transformer 整体架构3.Encoder的运作方式4.Decoder的运作方式5.AT 与 NAT6.Encoder 和 Decoder 之间的互动7.Training Transformer 1.了解Seq2Seq任务 NLP 的问题&#xff0c;都可以看做是 QA&#xff08;Question Answering&#x…

只要陪着你——来自歌手朱卫明的音乐与情感的交织

在这个五彩斑斓又纷繁复杂的世界中&#xff0c;情感是我们最珍贵的财富。有一种情感&#xff0c;它不受时间的限制&#xff0c;不受空间的束缚&#xff0c;它能够跨越四季&#xff0c;穿越风雨&#xff0c;那就是陪伴。朱卫明的歌声就是这种陪伴的象征&#xff0c;他用音乐为我…

vue自定义指令及常用的自定义指令封装

vue2 自定义指令 官网链接https://v2.cn.vuejs.org/v2/guide/custom-directive.html 指令注册 这里是一个 Vue2 的指令合集&#xff0c;详细的指令移步下面具体的指令文章&#xff0c;现在我们在这里要介绍如何在项目中统一管理和使用这些指令。 注册指令 单文件引入注册 …

机器学习的12个基础问题

1.阐述批归一化的意义 算法 1&#xff1a;批归一化变换&#xff0c;在一个 mini-batch 上应用于激活 x。 批归一化是一种用于训练神经网络模型的有效方法。这种方法的目标是对特征进行归一化处理&#xff08;使每层网络的输出都经过激活&#xff09;&#xff0c;得到标准差为 …

O_APPEND影响写入追加,而不影响读文件

O_APPEND 标志用于打开文件时&#xff0c;对写入操作进行追加。它并不直接影响读取文件的操作。 当使用 O_APPEND 标志打开文件时&#xff0c;写入操作会自动将数据追加到文件的末尾&#xff0c;而无论文件指针的位置在哪里。这对于避免并发写入时的竞争条件非常有用&#xff…

腾讯云服务器优惠活动大全页面_全站搜优惠合集

腾讯云推出优惠全站搜页面 https://curl.qcloud.com/PPrF9NFe 在这个页面可以一键查询所需云服务器、轻量应用服务器、数据库、存储、CDN、网络、安全、大数据等云产品优惠活动大全&#xff0c;活动打开如下图&#xff1a; 腾讯云优惠全站搜 腾讯云优惠全站搜页面 txybk.com/go…

java-IO流

File类 引入 【1】文件&#xff0c;目录&#xff1a; 文件&#xff1a; 内存中存放的数据在计算机关机后就会消失。要长久保存数据&#xff0c;就要使用硬盘、光盘、U 盘等设备。为了便于数据的管理和检索&#xff0c;引入了“文件”的概念。一篇文章、一段视频、一个可执…

Element的安装以及基本使用

Element是基于Vue的网站组件库&#xff0c;用于快捷构建网页 像上面这样的样式 官网地址 Element - 网站快速成型工具 安装 npm i element-ui -S 装包命令 npm install babel-plugin-component -D 安装好之后会在package.json里面显示版本 在node_modules中会自动初始化一个 …

opencv中叠加Sobel算子与Laplacian算子实现边缘检测

1 边缘检测介绍 图像边缘检测技术是图像处理和计算机视觉等领域最基本的问题&#xff0c;也是经典的技术难题之一。如何快速、精确地提取图像边缘信息&#xff0c;一直是国内外的研究热点&#xff0c;同时边缘的检测也是图像处理中的一个难题。早期的经典算法包括边缘算子方法…

记录一次API报文替换点滴

1. 需求 各位盆友在日常开发中&#xff0c;有没有遇到上游接口突然不合作了&#xff0c;临时需要切换其他接口的情况&#xff1f;这不巧了&#xff0c;博主团队近期遇到了&#xff0c;又尴尬又忐忑。 尴尬的是临时通知不合作了&#xff0c;事前没有任何提醒&#xff1b; 忐忑…

MQTT 介绍与学习 —— 筑梦之路

之前写过的相关文章&#xff1a; MQTT协议&#xff08;转载&#xff09;——筑梦之路_mqtt url-CSDN博客 k8s 部署mqtt —— 筑梦之路-CSDN博客 CentOS 7 搭建mqtt服务——筑梦之路_腾讯云宝塔搭 centos 7.9.2009 x86_64 建标准mqtt服务器-CSDN博客 mqtt简介 MQTT&#xff…