【JAVA】垃圾回收详解

2023-11-08


垃圾回收

垃圾回收,就是释放垃圾占用的空间,从而提升程序性能,防止内存泄露。当一个对象不再被需要时,该对象就需要被回收并释放空间。

Java 内存运行时数据区域包括程序计数器、虚拟机栈、本地方法栈、堆等区域。其中,程序计数器、虚拟机栈和本地方法栈都是线程私有的,当线程结束时,这些区域的生命周期也结束了,因此不需要过多考虑回收的问题。而是虚拟机管理的内存中最大的一块,堆中的内存的分配和回收是动态的,垃圾回收主要关注的是堆空间。


调用垃圾回收器的方法

调用垃圾回收器的方法是 gc ,该方法在 System 类和 Runtime 类中都存在。

java.lang.System.gc 等价于 java.lang.Runtime.getRuntime.gc 的简写,都是调用垃圾回收器。

Runtime 类中,方法 gc 是实例方法,方法 System.gc 是调用该方法的一种传统而便捷的方法。

System 类中,方法 gc 是静态方法,该方法会调用 Runtime 类中的 gc 方法。

方法 gc 的作用是提示 Java 虚拟机进行垃圾回收,该方法由系统自动调用,不需要人为调用。该方法被调用之后,由 Java 虚拟机决定是立即回收还是延迟回收


finalize 方法

与垃圾回收有关的另一个方法是 finalize 方法。该方法在 Object 类中被定义,在释放对象占用的内存之前会调用该方法。

该方法的默认实现不做任何事,如果必要,子类应该重写该方法,一般建议在该方法中释放对象持有的资源。


判断对象是否可回收

垃圾回收器在对堆进行回收之前,首先需要确定哪些对象是可回收的。常用的算法有两种,引用计数算法根搜索算法


引用计数算法

引用计数算法给每个对象添加引用计数器,用于记录对象被引用的计数,引用计数为 0 的对象即为可回收的对象。

虽然引用计数算法的实现简单,判定效率也很高,但是引用计数算法无法解决对象之间循环引用的情况。如果多个对象之间存在循环引用,则这些对象的引用计数永远不为 0,无法被回收。因此 Java 语言没有使用引用计数算法。


根搜索算法

主流的商用程序语言都是使用根搜索算法判断对象是否可回收。根搜索算法的思路是,从若干被称为 GC Roots 的对象开始进行搜索,不能到达的对象即为可回收的对象。

在 Java 中,GC Roots 一般包含下面几种对象:

  • 虚拟机栈中引用的对象;
  • 本地方法栈中的本地方法引用的对象;
  • 方法区中的类静态属性引用的对象;
  • 方法区中的常量引用的对象。

引用的分类

引用计数算法和根搜索算法都需要通过判断引用的方式判断对象是否可回收。

JDK 1.2 之后,Java 将引用分成四种,按照引用强度从高到低的顺序依次是:强引用、软引用、弱引用、虚引用。

  • 强引用:在程序代码中普遍存在的引用。垃圾回收器永远不会回收被强引用关联的对象。
  • 软引用:还有用但并非必需的对象。只有在系统将要发生内存溢出异常时,被软引用关联的对象才会被回收。在 JDK 1.2 之后,提供了 SoftReference 类实现软引用。
  • 弱引用:非必需的对象,其强度低于软引用。被弱引用关联的对象只能存活到下一次垃圾回收发生之前,当垃圾回收器工作时,被弱引用关联的对象一定会被回收。在 JDK 1.2 之后,提供了 WeakReference 类实现弱引用。
  • 虚引用:最弱的引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被回收时收到一个系统通知。在 JDK 1.2 之后,提供了 PhantomReference 类实现虚引用。

垃圾回收算法

标记—清除算法

标记—清除算法是最基础的垃圾回收算法,后续的垃圾收集算法都是基于标记—清除算法进行改进而得到的。标记—清除算法分为“标记”和“清除”两个阶段,首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。

标记—清除算法有两个主要缺点:

  • 效率问题:标记和清除的效率都不高
  • 空间问题:标记清除之后会产生大量不连续的内存碎片,导致程序在之后的运行过程中无法为较大对象找到足够的连续内存。

标记—整理算法

标记—整理算法是根据老年代的特点提出的。标记过程与标记—清除算法一样,但后续步骤不是直接回收被标记的对象,而是让所有存活的对象都向一端移动,然后清除边界以外的内存。


复制算法

复制算法的将可用内存分成大小相等的两块,每次只使用其中的一块,当用完一块内存时,将还存活着的对象复制到另外一块内存,然后把已使用过的内存空间一次清理掉。

复制算法解决了效率问题。由于每次都是对整个半区进行内存回收,因此在内存分配时不需要考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可。复制算法的优点是实现简单,运行高效,缺点是将内存缩小为了原来的一半,以及在对象存活率较高时复制操作的次数较多,导致效率降低。


分代收集算法

分代收集算法根据对象的存活周期不同将内存划分为多个区域,对每个区域选用不同的垃圾回收算法。

一般把 Java 堆分为新生代和老年代

  • 在新生代中,大多数对象的生命周期都很短,因此选用复制算法。
  • 在老年代中,对象存活率高,因此选用标记—清除算法或标记—整理算法。

分配内存与回收策略

Java 堆可以分成新生代和老年代,新生代又可以细分成 Eden 区、From Survivor 区、To Survivor 区等。对于不同的对象,有相应的内存分配规则。


Minor GCFull GC

Minor GC 指发生在新生代的垃圾回收操作。因为大多数对象的生命周期都很短,因此 Minor GC频繁执行,一般回收速度也比较快

Full GC 也称 Major GC ,指发生在老年代的垃圾回收操作。出现了 Full GC ,经常会伴随至少依次的 Minor GC 。老年代对象的存活时间长,因此 Full GC 很少执行,而且执行速度会比 Minor GC 很多。


对象的区分配

大多数情况下,对象在新生代 Eden 区分配,当 Eden 区空间不够时,发起 Minor GC。长期存活的对象进入老年代

大对象直接进入老年代。大对象是指需要连续内存空间的对象,最典型的大对象是那种很长的字符串以及数组。大对象对于虚拟机的内存分配而言是坏消息,经常出现大对象会导致内存还有不少空间时就提前触发垃圾回收以获取足够的连续空间分配给大对象。

将大对象直接在老年代中分配的目的是避免在 Eden 区和 Survivor 区之间出现大量内存复制。


动态对象年龄判定

虚拟机采用分代收集的思想管理内存,因此需要识别每个对象应该放在新生代还是老年代。虚拟机给每个对象定义了年龄计数器,对象在 Eden 区出生之后,如果经过第一次 Minor GC 之后仍然存活,将进入 Survivor 区,同时对象年龄变为 1,对象在 Survivor 区每经过一次 Minor GC 且存活,年龄就增加 1 ,增加到一定阈值时则进入老年代(阈值默认为 15 )。

为了能更好地适应不同程序的内存状况,虚拟机并不总是要求对象的年龄必须达到阈值才能进入老年代。如果在 Survivor 区中相同年龄的所有对象的空间总和大于 Survivor 区空间的一半,则年龄大于或等于该年龄的对象直接进入老年代


空间分配担保

在发生 Minor GC 之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象的空间总和,如果这个条件成立,那么 Minor GC 可以确保是安全的。

只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小,就会进行 Minor GC ,否则将进行 Full GC


来源:力扣(LeetCode)
链接:https://leetcode-cn.com/leetbook/read/java-interview-highlights/en7epe/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【JAVA】垃圾回收详解 的相关文章

随机推荐

  • SOA中的两个概念:编制(orchestration)和编排(choreography)

    以下是摘自 Understanding SOA with Web Services 中文版 关于两个概念的解释 编制 orchestration 和编排 choreography 是常用于描述 合成Web服务的两种方式 的术语 虽然它们有共
  • C 和 C++的区别 / struct 和 class 的区别 / 指针和引用的区别 / new 与 malloc 的区别 / 堆和栈的区别 / sizeof 和 strlen 的区别

    C 和 C 的区别 主要从以下三个方面来谈 设计思想 编程思想方面 语言特性方面 语法 内存管理 库 执行效率方面 C 和 C 的区别 C 是面向过程的语言 而 C 是面向对象的语言 因此 C 语言中有类和对象以及继承多态这样的面向对象语言
  • maskrcnn-benchmark训练自己数据集用于视觉分割

    1 标记数据用labelme 建议用ubuntu版本去做 因为window可能因为这个需要环境改变影响其他 自己犯过这个问题 https github com wkentaro labelme 2 labelme转化成coco数据集用于分割
  • Hyperlynx仿真操作小点

    一 改变传输线的属性 双击传输线 在对话框中选择要的线型 设置部分线的阻抗 点击edit coupling regions栏 选择右上方的edit stackup 编辑想要的叠层属性 通常改变顶底层和电源层 地层之间的PP厚度 10 8 5
  • 使用Python和XPath解析动态JSON数据

    JSON动态数据在Python中扮演着重要的角色 为开发者提供了处理实时和灵活数据的能力 Python作为一种强大的编程语言 提供了丰富的工具和库来处理动态JSON数据使得解析和处理动态JSON数据变得简单和高效 例如 使用内置的json模
  • python自动化处理,PPT处理

    一 PPT相关库介绍 安装python pptx库 同其他文件转换pptx2md rst2pptx 导入库 import pptx 初始化 ppt pptx Presentation 二 幻灯片层次结构说明 PPT文件结构 PPT文件结构指
  • 深入理解JVM—垃圾回收机制

    一 前言 明确垃圾收集器关注的部分 堆和方法区 着重学习如何确定哪些垃圾需要回收 垃圾回收算法以及GC触发条件 二 如何确定哪些垃圾需要回收 1 引用计数算法 在对象中添加一个引用计数器 每当有一个地方引用它时 计数器值就加一 当引用失效时
  • ROS2系统节点开机自启动

    要将ROS2节点设置为开机自启动 您可以创建一个systemd服务单元来管理它 一 创建launch文件 cd ros2 ws mkdir launch touch launch ros launch py 编辑内容 from launch
  • # 解析bt文件_PC端BT资源搜索及下载,诸位请节制!

    Hello大家好 这里是TopOne软件管家 毕竟要求的人太多了 今天将我测试最好的搭配给大家分享一下 当然 这个是站在我的角度 大家可以根据自己的使用情况进行调整 今天分享的是PC端 由于Mac限制 苹果电脑现只提供BT搜索软件 BT搜索
  • Windows下基于WSL2的Ubuntu开发环境搭建

    1 背景介绍 Windows是市场占有率最高的桌面操作系统 嵌入式开发领域一般需要搭建ubuntu虚拟机环境以实现linux下的交叉编译等工作 传统的Vmvare Ubuntu虚拟机安装过程繁琐且资源消耗巨大 自从Windows提供WSL2
  • 数据分析08——Pandas中对数据进行数据清洗

    0 前言 使用pandas修改数据是否会改变源数据 Pandas 对 DataFrame 的操作通常是针对原始数据本身而不是其副本的 例如 当我们使用 loc 或 iloc 方法选择 DataFrame 中的某行或某列并进行修改时 实际上是
  • python实现手势识别

    python实现手势识别 入门 使用open cv实现简单的手势识别 刚刚接触python不久 看到了很多有意思的项目 尤其时关于计算机视觉的 网上搜到了一些关于手势处理的实验 我在这儿简单的实现一下 PS 和那些大佬比起来真的是差远了 毕
  • Flink Sql使用mysql-cdc捕获多个表失败的问题

    问题描述 要捕获同一个库里的多个表的binlog 程序不报错 但是修改某个表后没有结果没有任何改变 fllinkSql的with语句 WITH connector mysql cdc hostname s port s username s
  • Linux安装anaconda3是否初始化的区别

    Linux安装anaconda3提示是否希望安装程序通过运行conda init来初始化Anaconda3 Do you wish the installer to initialize Anaconda3 by running conda
  • 数据结构1.1.1单链表的实现

    1 初始化链表节点内容 typedef struct char isbn 20 char name 10 double price Book typedef struct list Book date struct list next Li
  • GIT——! [rejected] master -> master (non-fast-forward)

    问题 rejected master gt master non fast forward error failed to push some refs to ssh 192 168 137 64 29418 51Selling git h
  • Maven的安装与使用

    一 简介 1 什么是Maven Maven翻译为 专家 内行 的意思 是著名Apache公司下基于Java开发的开源项目 Maven项目对象模型 POM 是一个项目管理工具软件 可以通过简短的中央信息描述来管理项目的搭建 报告和文档等步骤
  • JS+AES解密(CBC模式、输出HEX)

    if tokenMsgs const response await getMqttMsgService let mqttMsg response data msg state mqttconfigs mqttMsg const aesKey
  • 【工具类】发送邮件表格html生成类

    发送邮件的时候 有时候要自己拼html画一个表格 嫌麻烦就写了个工具类 核心类MailTableBuilder import java util MailTableCell author zgd date 2022 8 25 17 43 p
  • 【JAVA】垃圾回收详解

    文章目录 垃圾回收 调用垃圾回收器的方法 finalize 方法 判断对象是否可回收 引用计数算法 根搜索算法 引用的分类 垃圾回收算法 标记 清除算法 标记 整理算法 复制算法 分代收集算法 分配内存与回收策略 Minor GC 和 Fu