深入理解JVM(四)JVM的垃圾回收机制

2023-11-05

1 什么是垃圾回收机制

垃圾回收(Garbage Collection)是JVM垃圾回收器提供的一种用于死去的(不可能再被任何途径使用的)对象占据的内存空间的一种机制。

垃圾收集主要是针对堆和方法区进行,程序计数器、虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后也会消失,因此不需要对这三个区域进行垃圾回收。

2 Java中的引用类型

Java里有不同的引用类型,分别是强引用、软引用、弱引用和虚引用。

  • 强引用: 无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收掉被引用的对象
  • 软引用: SoftReference内存充足时不回收,内存不足时则回收
  • 弱引用: WeakReference 不管内存是否充足,只要GC一运行就会回收该引用对象
  • 虚引用: PhantomReference是最弱的一种引用关系,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知。
//强引用
Object object = new Object();
//软引用
SoftReference softReference=new SoftReference<>("1");
//弱引用
WeakReference weakReference=new WeakReference<>("2");
//虚引用
PhantomReference phantomReference = new PhantomReference("3",new ReferenceQueue());

3 如何判断对象是否可以被回收

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

判断对象是否存活一般有两种方式:
引用计数:在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加一;当引用失效时,计数器值就减一,计数为0时可以回收。此方法虽然简单,无法解决对象相互循环引用的问题。比如两个对象已经不可能再被访问,但是它们因为互相引用着对方,导致它们的引用计数都不为零,引用计数算法也就无法回收它们。
可达性分析:通过一系列称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为“引用链”(Reference Chain),如果某个对象到GC Roots间没有任何引用链相连,或者用图论的话来说就是从GC Roots到这个对象不可达时,则证明此对象是不可能再被使用的。
在这里插入图片描述

obj8、obj9、obj10都没有到GCRoots对象的引用链,即便obj9和obj10之间有引用链,他们还是会被当成垃圾处理,可以进行回收。

在 Java 中 GC Roots 一般包含以下内容:

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

4 方法区的垃圾收集

方法区的垃圾收集主要回收两部分内容:废弃的常量和不再使用的类型。假如一个字符串“java”曾经进入常量池中,但是当前系统又没有任何一个字符串对象的值是“java”,换句话说,已经没有任何字符串对象引用常量池中的“java”常量,且虚拟机中也没有其他地方引用这个字面量。如果在这时发生内存回收,而且垃圾收集器判断确有必要的话,这个“java”常量就将会被系统清理出常量池。

5 垃圾收集算法

5.1 标记-清除(Mark-Sweep)算法

首先标记出所有需要回收的对象,在标记完成后,统一回收掉所有被标记的对象,也可以反过来,标记存活的对象,统一回收所有未被标记的对象。
在这里插入图片描述
缺点:

  • 执行效率不稳定

如果Java堆中包含大量对象,而且其中大部分是需要被回收的,这时必须进行大量标记和清除的动作,导致标记和清除两个过程的执行效率都随对象数量增长而降低。

  • 内存空间的碎片化问题

标记、清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致当以后在程序运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

5.2 标记整理(Mark-Compact)算法

首先标记出所有需要回收的对象,在标记完成后,让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存。
在这里插入图片描述
缺点:
如果移动存活对象,尤其是在老年代这种每次回收都有大量对象存活区域,移动存活对象并更新所有引用这些对象的地方将会是一种极为负重的操作,而且这种对象移动操作必须全程暂停用户应用程序才能进行,像这样的停顿被描述为"Stop The World"。

5.3 复制算法

将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
在这里插入图片描述
缺点:
可用内存缩小为了原来的一半,空间浪费太多

5.4 分代收集算法

根据对象存活周期的不同将内存划分为几块,一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。

在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用标记-清理或者标记-整理算法来进行回收。

6 内存分配与回收策略

在这里插入图片描述

6.1 内存分配策略

6.1.1 内存分配
  • 对象优先在 Eden 分配。大多数情况下,对象在新生代 Eden 区分配,当 Eden 区空间不够时,发起 Minor GC。
  • 大对象直接进入老年代。大对象是指需要连续内存空间的对象,最典型的大对象是那种很长的字符串以及数组。
  • 长期存活的对象进入老年代。对象在 Eden 出生并经过 Minor GC 依然存活,将移动到 Survivor 中,年龄就增加 1 岁,增加到一定年龄(默认是15,可以使用-XX:MaxTenuringThreshold 参数来进行设置)则移动到老年代中。
  • 动态对象年龄判定。Survivor区的对象年龄从小到大进行累加,当累加到X年龄时的总和大于50%(可以使用-XX:TargetSurvivorRatio 参数来进行设置),那么比年龄X大的对象都会晋升到老年代,不必达到MaxTenuringThreshold 中要求的年龄。
  • 空间分配担保。在发生 Minor GC 之前,虚拟机先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果大于,那么就进行 Minor GC 。 如果不成立的话虚拟机会查看 HandlePromotionFailure 设置值是否允许担保失败,如果允许那么就会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次 Minor GC;如果小于,或者 HandlePromotionFailure 设置不允许冒险,那么就要进行一次 Full GC。
    在这里插入图片描述
6.1.2 堆的年轻代为什么要有两个Survivor区
  • 如果没有Survivor区,每触发一次Minor GC,就会把Eden区的对象复制到老年代,这样当老年代满了之后会触发Major GC/Full GC(通常伴随着MinorGC),比较耗时,所以必须有Survivor区;
  • 如果只有一个survivor区,刚刚新建的对象在Eden中,一旦Eden满了,触发一次Minor
    GC,Eden中的存活对象就会被移动到Survivor区。下一次Eden满了的时候,此时进行Minor GC,Eden和Survivor各有一些存活对象,如果此时把Eden区的存活对象硬放到Survivor区,很明显这两部分对象所占有的内存是不连续的,也就导致了内存碎片化。
  • 如果有两个survivor区,新建的对象在Eden中,经历一次Minor GC,Eden中的存活对象就会被移动到第一块survivor space S0,Eden被清空;等Eden区再满了,就再触发一次Minor GC,Eden和S0中的存活对象又会被复制送入第二块survivor space S1,S0和Eden被清空,然后下一轮S0与S1交换角色,如此循环往复,这就解决了内存碎片化的问题。

6.2 内存回收策略

6.2.1 Minor GC 、Major GC、Mixed GC和 Full GC的区别
  • 新生代收集(Minor GC/Young GC):指目标只是新生代的垃圾收集。
  • 老年代收集(Major GC/Old GC):指目标只是老年代的垃圾收集。“Major GC”这个说法现在有点混淆,在不同资料上常有不同所指,需按上下文区分到底是指老年代的收集还是整堆收集。
  • 混合收集(Mixed GC):指目标是收集整个新生代以及部分老年代的垃圾收集。
  • 整堆收集(Full GC):收集整个Java堆和方法区的垃圾收集。
6.2.2 Minor GC触发条件

当Eden区满时,触发Minor GC,而Survivor区满不会触发Minor GC。

6.2.3 Full GC触发条件
  • System.gc()方法的调用(此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率,也增加了间歇性停顿的次数。强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存)
  • 老年代空间不足
  • 空间分配担保失败
  • 方法区空间不足
  • 由 Eden 区、S0 区向 S1 复制的对象太大,导致直接进入老年代,但是老年代内存不够
  • CMS GC时出现concurrent mode failure(执行 CMS GC 的过程中同时有对象要放入老年代,而此时老年代空间不足,便会报 Concurrent Mode Failure 错误,并触发 Full GC)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深入理解JVM(四)JVM的垃圾回收机制 的相关文章

  • 如何创建约束输入流以仅读取文件的一部分?

    我想创建一个仅限于文件中一定范围的字节的输入流 例如从位置 0 到 100 的字节 这样 一旦到达第 100 个字节 客户端代码就应该看到 EOF The read 的方法InputStream一次读取一个字节 你可以写一个子类InputS
  • 使用现有同级属性值对属性进行 Jackson 多态反序列化

    我有一个现有的Request Response协议使用JSON我无法控制 示例1 响应JSON不需要任何多态反序列化 name simple response params success true 示例2 响应JSON需要对 params
  • JMenuItem:如何设置具有3个键的加速器?

    请看下面的代码 import java awt import java awt event import javax swing public class MenuActions extends JFrame private JMenuBa
  • 没有绑定 play.db.Database 的实现

    我在使用 hikaricp 时访问数据库时遇到问题 这是我的reference conf play modules enabled play api db DBModule enabled play api db HikariCPModul
  • 以编程方式滚动 NatTable

    关于 stackoverflow 的第一个问题 类似的问题here https stackoverflow com questions 3531081 scrolling swt table programmatically 只有我想滚动N
  • 如何测试两个 Joda-Time DateTime 对象几乎相等?

    在单元测试中 我经常使用返回DateTime于或关于now 有没有办法说actual日期时间在几秒之内actual约会时间 这听起来是个坏主意 单元测试不应该以任何方式依赖于当前的实际时间 这就是为什么注入一些接口是一个很好的做法 称为Cl
  • 您最好的 Swing 设计模式和技巧是什么? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 在 IntelliJ IDEA 中编辑并继续?

    使用 IntelliJ IDEA 社区版进行调试时是否可以编辑一些代码 我在选项中找不到这个功能 是的 这就是所谓的 热插拔 您可以在调试过程中编译修改后的代码 并且类文件将被替换 直到您停止调试 确保在调试器设置中启用 HotSwap 选
  • Unwrap 当使用 Collectors maxBy 和 groupingBy 时可选

    我有一堂课 有一个String and an int field public class Data private String name private int value private Data String name int va
  • Jenkins 中未找到 Maven

    我正在 Jenkins 中运行我的 Maven Spring 项目 只是第一次测试它 使用 shell 脚本选项 mvn spring boot run 我收到构建错误 Users Shared Jenkins tmp jenkins808
  • 如何从 Coldfusion 2016 中加载 jsoup Java 库?

    TLDR CreateObject 函数会抛出异常 java lang ClassNotFoundException 因为它看不到 java 类 JAR 文件 有什么想法我做错了什么吗 谢谢 Application cfc 的内容
  • 如何将一个组件放在其他组件之上?

    我有一个JScrollPanel其中包括一个大面板 其本身包括 3 个内面板 我想将一个面板 例如 放在一个特殊的位置 以便始终可以看到 我的意思是用户可以滚动到想要的任何地方 但该面板始终位于其他组件的顶部并且不会移动 我试图通过这样做J
  • 全屏 Swing 组件无法在 Mac OS X Mountain Lion 上的 Java 7 上接收键盘输入

    12 21 更新 7u10 最近发布 确认 问题仍然存在 值得庆幸的是 解决方法仍然有效 11 7 更新 我们有一个解决方法 来自 Oracle 的 Leonid Romanov 在 openjdk java net 邮件列表上提供了一些关
  • Spring Hibernate 4 支持

    我正在使用 Hibernate 4 CR1 我的应用程序之前使用 Spring hibernate 支持 版本 3 我还没有找到任何相关信息 是否有任何迹象表明 Spring 何时 或哪个版本 将提供对 Hibernate 4 的支持 UP
  • 获取 javax.crypto.IllegalBlockSizeException:使用填充密码解密时输入长度必须是 16 的倍数?

    使用 tomcat 我有两个 Web 应用程序 即 app1 和 app2 我以加密形式 使用下面的代码 将 url 从 app1 发送到 app2 然后在app2 我解密了这个加密的网址 但我在第 50 行低于异常decryp方法 Get
  • 使用 jsch 将远程服务器中的目录移动到同一远程服务器中的另一个位置

    我正在使用 JSCH API 通过 sftp 连接到远程服务器 我需要将远程服务器中的目录从位置 A 移动到位置 B 看起来像方法channelsftp put src dest 只允许移动文件而不移动目录 有人可以解释一下我该怎么做吗 您
  • 找出网络上所有活动机器的IP

    如何找到 LAN 上所有当前活动计算机的 IP 如何编写一个可以在任何子网上运行的通用程序 我目前正在这样做 尝试 isReachable 是否到达我子网上的所有机器 如果他们这样做 请存储他们的 IP 地址 无论如何 是否有其他方法可以手
  • JSON 解析为 Java - Android 应用程序

    我需要在 Java Android 应用程序中解析 json 字符串的帮助 JSON 文件的文本 data columns location id name description latitude longitude error type
  • 客户端和服务器之间的安全连接

    我正在开发一个服务器组件 它将为嵌入式客户端的请求提供服务 这也在我的控制之下 现在一切都是测试版 安全性是这样的 客户端通过 https 发送用户名 密码 服务器返回访问令牌 客户端使用自定义标头中的访问令牌通过 http 发出进一步请求
  • 无法声明接口:资源繁忙

    我正在使用 USB4Java 低级版本 并且基本上是根据这段代码工作的here http www mets blog com java usb communication usb4java 我在 Ubuntu 中工作 遇到了有关权限的问题

随机推荐

  • 电脑提示‘您需要来自Administration的权限才能对此文件夹进行更改’怎么删除文件...

    电脑提示 您需要来自Administration的权限才能对此文件夹进行更改 怎么删除文件 应该怎么做 win7系统需要定期删除一些无用的文件 扩大内存空间 但是在删除文件的时候弹出提示 您需要来自Administrators的权限才能对此
  • llvm libLLVMCore源码分析 02 - Value Class

    源码路径 llvm include llvm IR Value h llvm include llvm IR ValueHandle h llvm Value Class 在llvm中 Value类是所有程序计算出的值的类 如Argumen
  • 一个外国的好网站 http://www.ilovejackdaniels.com/

    正则表达式大区 魔兽快捷键 呵呵 转载于 https www cnblogs com yamajia archive 2007 12 04 981843 html
  • Hive 基础知识

    目录 1 基础概念 1 1 定义 1 2 组件 1 3 元数据 1 4 内部表和外部表 2 Hive与关系型数据库的对比 3 Hive 数据存储 4 参考文献 1 基础概念 1 1 定义 Hive是一个基于Hadoop的数据仓库基础设施工具
  • notepad++安装十六进制插件备注

    notepad 安装十六进制插件备注 notepad 下载地址 https notepad plus plus org notepad 16进制插件下载位置 https github com chcg NPP HexEdit release
  • QKL123

    作者 QKL123 QKL123区块链排行榜包括区块链项目 区块链交易平台 区块链媒体 区块链公众号 区块链矿机 区块链矿池 EOS Dapp ETH Dapp 区块链钱包九大榜单 相对第二期 2019年02月 榜单 该期首次新增ETH D
  • java JDWP调试接口任意命令执行漏洞

    点击 仙网攻城狮 关注我们哦 不当想研发的渗透人不是好运维 让我们每天进步一点点 简介 JDWP Java DEbugger Wire Protocol 即Java调试线协议 是一个为Java调试而设计的通讯交互协议 它定义了调试器和被调试
  • 【数据结构】一、顺序表的基本操作(C语言)

    顺序表的定义 初始化 创建 打印 按值查找 插入 时间复杂度为O n 删除 时间复杂度为O n 销毁 合并两个顺序表 include
  • AI 绘画Stable Diffusion 研究(一)sd整合包v4.2 版本安装说明

    部署包作者 秋葉aaaki 免责声明 本安装包及启动器免费提供 无任何盈利目的 大家好 我是风雨无阻 众所周知 StableDiffusion 是非常强大的AI绘图工具 需要详细了解StableDiffusion的朋友 可查看我之前的这篇文
  • IntelliJ IDEA插件的Jrebel激活踩坑【内网离线使用】

    前言 Jrebel默认是需要外网在每一次使用时实时激活的 但是我们好多情况都是内网使用 所以我查了很多资料找到了一个解决方案 Jrebel 破解方法 https www jb51 net article 199354 htm Jrebel
  • python滚动的后推任意时点

    有几个关键点 对时间的循环 可以使用pandas的date range函数 比较容易一些 后推任意时点 使用dateutil relativedelta的relativedelta 可以以准确地指定日期后推 示例代码 比如 循环2020 0
  • react+antd出现preventDefault()警告报错

    react项目遇到如下报错 This synthetic event is reused for performance reasons If you re seeing this you re accessing the method p
  • 【C++】类和对象-多态

    1 多态的基本语法 代码 include
  • 【微信小程序】小程序长按复制文本

    微信小程序的文本 要具有长按复制功能 必须满足两个条件 文本在
  • Python类、模块、包

    http www cppblog com len archive 2008 07 24 57078 html Python在处理功能复用和功能颗粒度划分时采用了类 模块 包的结构 这种处理跟C 中的类和名字空间类似 但更接近于Java所采用
  • linux开发板通过网线连接电脑(win10)连接网络问题

    最近开始学习嵌入式Linux开发 使用野火imx6ull开发板 想把开发板通过网线连接到笔记本 笔记本连接WiFi 共享使用网络 查询了很多资料后成功实现 我现在把这个方法分享出来 1 禁用防火墙功能 打开网络和共享中心 gt window
  • .net dapper简单使用

    以本地mysql数据库为例 准备工作 新建数据库 新建表 例如book表 然后定义Book类 book表和Book类应对应 这样dapper才能把他们映射好 在appsettings json中配置数据库连接 ConnectionStrin
  • pytorch autograd计算标量函数二阶导数

    计算标量函数 y x 3 s i n
  • 微信公众号实现简易的物联网控制(一)

    这篇主要说说如何通过微信公众号来查看室内传感器数据 至于硬件部分和物联网平台以后再详细说明 准备工作 1 申请微信公众号 2 搭建云服务器 首先说明一下整体流程 用户发送相应的指令到公众号后台 服务器根据指令的内容调用OneNET的API获
  • 深入理解JVM(四)JVM的垃圾回收机制

    文章目录 1 什么是垃圾回收机制 2 Java中的引用类型 3 如何判断对象是否可以被回收 4 方法区的垃圾收集 5 垃圾收集算法 5 1 标记 清除 Mark Sweep 算法 5 2 标记整理 Mark Compact 算法 5 3 复