【JVM】对象死亡判断

news2024/11/26 6:22:11

文章目录

  • 简述
  • 引用计数算法
  • 可达性分析算法
  • 4种对象引用
  • finalize()方法
  • 回收方法区

简述

在堆里面存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”(“死去”即不可能再被任何途径使用的对 象)了。

引用计数算法

引用计数算法是一种用于内存管理的垃圾回收算法。它的核心思想是为每个对象维护一个引用计数,表示有多少个引用指向该对象。当引用计数为零时,说明该对象不再被任何引用指向,可以安全地回收内存。

引用计数算法的主要特点和优点包括:

  1. 简单:引用计数算法非常简单直观,每次对象的引用发生变化时,引用计数都会相应地增加或减少。
  2. 实时性:由于引用计数是实时维护的,一旦引用计数为零,就可以立即回收对象,不需要等待垃圾回收器的运行。
  3. 最小化停顿时间:引用计数算法通常不需要执行全局性的垃圾回收操作,因此不会引起大规模的内存回收导致的长时间停顿。

然而,引用计数算法也存在一些明显的缺点:

  1. 循环引用问题:引用计数算法无法处理循环引用的情况。如果两个或多个对象相互引用,它们的引用计数永远不会为零,即使它们已经不再被程序使用。这会导致内存泄漏。
  2. 性能开销:每次引用发生变化时,都需要增加或减少引用计数,这会增加额外的性能开销。此外,需要额外的内存来存储引用计数。
  3. 不适用于多线程环境:在多线程环境中,引用计数需要进行原子操作,以确保计数的准确性。这会引入额外的开销和复杂性。

综合考虑,引用计数算法在简单场景中可能是一种有效的垃圾回收方法,但在复杂的应用程序中通常不是首选。许多现代的编程语言和运行时环境使用基于引用计数的回收算法与其他算法(如标记-清除、标记-整理等)相结合,以克服引用计数算法的缺点,提高内存管理的效率和可靠性。

可达性分析算法

该算法的基本思路就是通过 一系列称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为“引用链”(Reference Chain),如果某个对象到GC Roots间没有任何引用链相连, 或者用图论的话来说就是从GC Roots到这个对象不可达时,则证明此对象是不可能再被使用的。

下图中的对象object 5、object 6、object 7虽然互有关联,但是它们到GC Roots是不可达的, 因此它们将会被判定为可回收的对象。

image-20230903223251580

在Java技术体系里面,固定可作为GC Roots的对象包括以下几种:

  • 在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的 参数、局部变量、临时变量等。

  • 在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量。

  • 在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用。

  • 在本地方法栈中JNI(即通常所说的Native方法)引用的对象。

  • Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如 NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。

  • 所有被同步锁(synchronized关键字)持有的对象。 ·反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。

除了这些固定的GC Roots集合以外,根据用户所选用的垃圾收集器以及当前回收的内存区域不 同,还可以有其他对象“临时性”地加入,共同构成完整GC Roots集合。

可达性分析算法的优点是能够准确识别出不再被程序引用的对象,因此可以有效地回收内存,避免内存泄漏。然而,它的缺点是需要遍历整个对象图,因此在对象数量庞大、引用关系复杂的情况下,可能会消耗较多的时间和计算资源。因此,现代的垃圾回收器通常会结合不同的回收算法来优化性能。

4种对象引用

在JDK 1.2版之后,Java对引用的概念进行了扩充,将引用分为强引用(Strongly Re-ference)、软 引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)4种,这4种引用强度依次逐渐减弱。

四种不同类型的引用,它们分别是:

  1. 强引用(Strong Reference)
    • 强引用是最常见的引用类型。
    • 当一个对象具有强引用时,垃圾回收器不会回收该对象,即使内存不足时也不会回收。
    • 只有当该对象的所有强引用都失效时,对象才会被回收
  2. 软引用(Soft Reference)
    • 软引用用于描述一些还有用但并非必需的对象。
    • 当内存不足时,垃圾回收器可能会回收被软引用指向的对象,但在内存足够的情况下,不会回收它们
    • 可以通过java.lang.ref.SoftReference类来创建软引用。
  3. 弱引用(Weak Reference)
    • 弱引用用于描述非必需的对象,通常用于缓存。
    • 弱引用指向的对象在下一次垃圾回收时就会被回收,无论内存是否足够
    • 可以通过java.lang.ref.WeakReference类来创建弱引用。
  4. 虚引用(Phantom Reference)
    • 虚引用是最弱的引用类型,通常用于跟踪对象被垃圾回收的状态。
    • 虚引用无法通过它访问对象的数据或者方法,它主要用于在对象被回收之前收到一个系统通知
    • 可以通过java.lang.ref.PhantomReference类来创建虚引用。

这些不同类型的引用允许开发者更灵活地控制对象的生命周期。例如,软引用和弱引用通常用于缓存,允许缓存中的对象在内存不足时被回收,从而避免内存溢出。虚引用则可以用于执行一些清理操作或者记录对象被垃圾回收的情况。需要根据具体的需求选择适当的引用类型。

finalize()方法

finalize() 方法是Java中的一个特殊方法,它属于java.lang.Object类,用于在对象被垃圾回收之前执行一些清理和资源释放操作。虽然它存在,但是从Java 9 开始,已经被标记为“过时”(deprecated),因为它具有一些问题和不稳定性,不建议在新代码中使用。

以下是有关 finalize() 方法的一些重要信息和注意事项:

  1. finalize() 方法的签名

    protected void finalize() throws Throwable {
        // 执行清理和资源释放操作
    }
    

    finalize() 方法的访问修饰符为 protected,表示只有同一类或其子类中的方法才能调用它。

  2. finalize() 方法的执行时机

    • finalize() 方法的执行时机不确定,不同的垃圾回收器在不同的情况下执行它。有些垃圾回收器可能根本不执行它。
    • 在对象被垃圾回收之前,垃圾回收器会首先调用 finalize() 方法,然后才会回收对象。但是不能保证 finalize() 方法一定会被执行,因此不应该依赖它来进行资源释放或清理操作。
  3. finalize() 方法的问题

    • finalize() 方法的执行时机不确定,可能会导致资源释放的延迟。
    • 在执行 finalize() 方法期间,对象仍然处于"活跃"状态,可能导致一些并发问题。
    • 由于不稳定性和性能问题,Java 9 引入了更先进的垃圾回收机制,逐渐减少了对 finalize() 方法的依赖。
  4. 建议的替代方法

    • 对于资源释放,应该使用 try-with-resourcesfinally 块等结构来确保及时释放资源。
    • 对于对象的生命周期管理,应该采用更可靠的方法,如弱引用、虚引用等,而不是依赖于 finalize() 方法。

总之,finalize() 方法虽然存在,但不再被推荐使用,因为它存在一些问题和不确定性,可能导致代码的不稳定性和性能问题。在现代Java编程中,应该使用更可靠和可控的方式来管理对象的生命周期和资源释放。

注意:任何一个对象的finalize()方法都只会被系统自动调用一次

回收方法区

Java虚拟机的方法区(Method Area)通常不会像堆内存那样被垃圾回收器进行垃圾回收。方法区主要用于存储类的结构信息、常量、静态变量以及字节码等,这些数据在整个程序的生命周期内都会被加载和使用,不会因对象的可达性而被回收。

然而,尽管方法区通常不会被垃圾回收,但在某些情况下,方法区中的一些数据可能会被回收或卸载:

  1. 无用的类卸载:当一个类不再被引用,并且不再被任何活动的类加载器加载时,这个类可能会被卸载,其在方法区中的相关信息也会被回收。这个过程通常发生在类加载器被回收时,例如在Web应用程序重新加载时。

  2. 常量池中的无用常量回收:在运行时常量池中的一些常量,特别是字符串常量,可能会因为没有引用而被回收。

  3. 优化技术:一些Java虚拟机实现采用了方法区中的数据的优化技术,可以在运行时进行热替换(HotSwap)或类的动态生成,这些技术可能会导致方法区中的一些数据被回收或替换。

需要注意的是,方法区的回收和内存管理与堆内存的垃圾回收不同。通常,方法区的内存管理和回收是由Java虚拟机自己负责的,而不需要开发者干预。而堆内存的垃圾回收通常涉及到开发者手动管理和代码中的对象引用关系。在Java 8及之后的版本中,方法区被元数据区(Metaspace)取代,它的管理方式也有所不同,包括了更灵活的内存管理机制。

在大量使用反射、动态代理、CGLib等字节码框架,动态生成JSP以及OSGi这类频繁自定义类加载 器的场景中,通常都需要Java虚拟机具备类型卸载的能力,以保证不会对方法区造成过大的内存压力。

综上所述,方法区通常不需要显式进行回收操作,而是由Java虚拟机自动管理。开发者需要关注的是对象的生命周期和内存管理,而方法区的管理通常不需要额外的干预。

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

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

相关文章

(17)线程的实例认识:wait,waitany,waitall,及经典死锁问题

一、文件构成 1、界面:一个textbox,四个button。 2、程序:前面(15)的book类与data类 private void AppendLine(string s){txtInfo.AppendText(string.IsNullOrEmpty(txtInfo.Text) ? s : $"{Environment.NewLine}{s}");…

Redis 7 第八讲 集群模式(cluster)架构篇

集群架构 Redis 集群架构图 集群定义 Redis 集群是一个提供在多个Redis节点间共享数据的程序集;Redis集群可以支持多个master 应用场景 Redis集群支持多个master,每个master又可以挂载多个slave读写分离支持数据的高可用支持海量数据的读写存储操作集群自带Sentinel的故障…

看懂UML类图

UML 统一建模语言(Unified Modeling Language,UML)是一种为面向对象系统的产品进行说明、可视化和编制文档的一种标准语言,是非专利的第三代建模和规约语言。UML是面向对象设计的建模工具,独立于任何具体程序设计语言。 类的表示 首先看那个…

ROS2中如何从欧拉角转换成四元素

ROS1中使用from tf.transformations import quaternion_from_euler导入quaternion_from_euler()即可调用。而ROS2中默认没有安装,需要单独安装一下ros-galactic-tf-transformations(我使用的ROS2是galactic,根据版本名不同做相应修改即可): …

Python GUI入门——tkinter编辑框、复选框、下拉菜单和按钮文本框的使用

简介 接上一次的tkinter编写界面相关内容,丰富点常用控件的方法,学会了这些控件布局和相关方 法属性,能够满足日常小工具的制作需求了。 搭建的界面框架如下图所示,功能可以自己添加。 界面代码 # -*- coding: utf-8 -*- impor…

第五章 树于二叉树 七、树和森林的遍历(广度优先遍历、深度优先遍历)

1、树的遍历 树是一种递归定义的数据结构,所以我们可以使用递归实现遍历。 (1)先根遍历(最先访问根节点)(深度优先遍历) 1.使用孩子兄弟表示法将其转化为二叉树的形式。 2.使用先序遍历二叉树…

面试2:通用能力

15丨如何做好开场:给自我介绍加“特效 第一层,满足面试官对信息的期待 这是对自我介绍的基本要求,把个人信息、主要经历、经验和技能有条理地组织起来, 有逻辑地讲出来。需要找出多段经历的关联性和发展变化,形成连…

分布式事务之 Seata 的部署和集成

文章目录 一、部署Seata的tc-server1.下载2.解压3.修改配置4.在nacos添加配置5.创建数据库表6.启动TC服务 二、Docker 中跑 Seata三、微服务集成seata1.引入依赖2.修改配置文件 四、TC服务的高可用和异地容灾1.模拟异地容灾的TC集群2.将事务组映射配置到nacos3.微服务读取nacos…

Linux下go环境安装、环境配置并执行第一个go程序

一、安装 1.Golang对Linux的内核版本要求 GO对Linux内核版本最低要求是 2.6.23,对应要求操作系统版本是: RHEL 6.0CentOS 6.0即,不支持 (RHEL 和 CentOS) 的 (4.x or 5.x)。2.下载golang的代码版本 Golang的官网下载地址:https:…

Presto 之Pipeline

一. 前言 我们知道在Presto中有个叫Pipeline的概念,Pipeline其实就是一条包含各个算子的流水线,如下所示。本文主要介绍在Presto中,Pipeline是如何划分的。 二. Pipeline 在Presto中,一个Stage中包括一个或者多个Pipeline&#xf…

JavaWeb项目基础配置

这里写目录标题 前言1.pom.xml2.webxml3.连接JDBC4.常用代码4.1获取时间4.2实现上传文件需要用到第三方库fileupload 常用快捷键常用操作Tomcat基础操作&#xff1a; 前言 本文主要讲述了 1.pom.xml <?xml version"1.0" encoding"UTF-8"?><pro…

9.2QTday4作业

1 闹钟 头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QtDebug> #include <QLabel> //标签类 #include <QLineEdit> //行编辑器类 #include <QPushButton> //按钮类 #include <QTextEdit> //文本编辑器…

STM32定时器定时及其应用

STM32定时器定时及其应用 定时器概述☆定时器相关配置CubeMX工程配置及程序实现固件库程序设计及实现 定时器概述 1. 工作原理 使用精准的时基&#xff0c;通过硬件的方式&#xff0c;实现定时功能。定时器核心就是计数器 2. 定时器分类   基本定时器&#xff08;TIM6~TIM7…

SiameseNet实战中文文本匹配任务

引言 本文我们通过SiameseNet模型来完成中文文本匹配任务&#xff0c;其中包含了文本匹配任务一般套路&#xff0c;后续只需要修改实现的模型。 数据准备 数据准备包括 构建词表(Vocabulary)构建数据集(Dataset) 本次用的是LCQMC通用领域问题匹配数据集&#xff0c;它已经…

RK3568-android11-适配ov13850摄像头

硬件连接 主要分为两部分: mipi接口:传输摄像头数据 i2c接口:配置摄像头和对焦马达芯片寄存器相关驱动 |-- arch/arm64/boot/dts/rockchip DTS配置文件 |-- drivers/phy/rockchip/|-- phy-rockchip-mipi-rx.c mipi dphy 驱动 |-- drivers/media||-- platform/rockchip/isp1…

20230903-闹钟

app.cpp #include "app.h" #include "ui_app.h" int k1 true;APP::APP(QWidget *parent):QWidget(parent),ui(new Ui::APP) {ui->setupUi(this);this->resize(380,300);this->setStyleSheet("background-color:cyan;");//设置样式spe…

关于指针的一些练习(1)

1. int main() {int a[3][2] { (0,1),(2,3),(4,5) };int* p;p a[0];printf("%d", p[0]);return 0; } 解析&#xff1a;a是一个3行2列的二维数组&#xff0c;对他进行初始化时大括号里面是逗号表达式&#xff0c;根据逗号表达式可以得到a数组中元素为1&#xff0c…

知识图谱推理研究综述9.3

综述分类 根据样本量大小的不同&#xff0c;将知识图谱推理方法分为多样本推理、少样本推理和零与单样本推理 KG定义&#xff1a;&#xff08;Y&#xff09; 知识图谱是以图的形式表示真实世界的实体与关系之间关系的知识库。 具体来说知识图谱是通过将应用数学、图形学、信…

培训机构如何利用小程序提升服务质量

近年来&#xff0c;小程序成为了许多企业和机构进行线上业务拓展的新方式。对于培训机构来说&#xff0c;构建一个具有吸引力的小程序可以帮助他们更好地与学员进行互动和沟通&#xff0c;并提供更便捷的学习服务。那么&#xff0c;如何使用第三方制作平台来构建一个具有吸引力…

线性代数的学习和整理18:什么是维度,什么是秩?关于秩的各种定理 (未完成)

目录 1 矩阵的秩 矩阵的秩 2 求秩的方法 矩阵的维度秩 矩阵的维度 向量的模&#xff0c;矩阵的模-没有把&#xff0c;难道是面积&#xff1f; 矩阵的平直概念 5 矩阵的初等变换&#xff08;矩阵等价概念的引出&#xff09; 0 问题引出&#xff1a;什么是秩&#xff1f;…