Java GC基础知识

这篇具有很好参考价值的文章主要介绍了Java GC基础知识。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 对象存活判断

1.1 引用计数

在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加一;当引用失效时,计数器值就减一;任何时刻计数器为零的对象就是不可 能再被使用的

引用计数法的缺陷:

public class ReferenceCountingGC {
    public Object instance = null;
    private static final int _1MB = 1024 * 1024;
    /**
    * 这个成员属性的唯一意义就是占点内存,以便能在GC日志中看清楚是否有回收过
    */
    private byte[] bigSize = new byte[2 * _1MB];
    public static void testGC() {
        ReferenceCountingGC objA = new ReferenceCountingGC();
        ReferenceCountingGC objB = new ReferenceCountingGC();
        objA.instance = objB;
        objB.instance = objA;
        objA = null;
        objB = null;
        // 假设在这行发生GC,objA和objB是否能被回收?
        System.gc();
    }
}

如果使用引用计数法objAobjB除互相引用外没有任何其他引用,但是无法被回收。

1.2 可达性分析

通过一些了GC Roots的根对象作为起点集,根据引用关系向下搜索,搜索过程所走过的路径称为引用链,如果某个对象和GC Roots之间没有任何引用链,则该对象不可达,需要被回收。

GC Roots 对象

  • 虚拟机栈(局部变量表)中引用的对象
  • 方法区中静态属性引用的对象
  • 方法区在常量引用的对象
  • 本地方法栈中Native方法引用的对象
  • Java虚拟机内部的引用
  • 被同步锁持有的对象
  • 等等

Java 引用

引用类型 描述
强引用 Object obj = new Object(); 垃圾回收器永远不会回收强引用对象
软引用 SoftReference; 系统发生内存溢出异常前,会回收软引用对象
弱引用 WeakReference; 无论内存是否足够,垃圾回收时都会回收弱引用对象
虚引用 PhantomReference; 该对象设置虚引用关联,唯一目的是该对象被回收时会收到一个系统通知

1.3 并发可达性分析

可达性分析在并发环境下存在的问题

问题1: 原本消亡的对象错误标记为存活对象(可容忍)
问题2: 原本存活的对象错误标记为消亡对象(不可容忍,导致程序出错)

可达性分析过程 —— 三色标记

  • 黑色节点: 对象已经被垃圾收集器访问过,且该对象的所有引用均已扫描
  • 灰色节点: 对象已经被垃圾收集器访问过,但该对象至少还有一个引用未被扫描
  • 白色节点: 对象尚未被垃圾收集器访问,可达性分析结束后,节点仍然为白色,则标识该对象不可达

问题2出现的原因: 同时满足以下两个条件

  • 并发标记期间程序增加一条或多条黑色对象到白色对象的引用
  • 并发标记期间删除了所有灰色对象到该白色对象的直接或间接引用

因为黑色对象已经不会再被访问,所以新增的引用无法生效;同时删除了所有其他灰色对象到该白色对象的直接或间接引用,所以该对象无法从其他引用链访问到,导致存活对象被错误标记为消亡对象。

解决方案

  • 增量更新: 当黑色对象插入新的指向白色对象的引用关系时,就将这个新插入的引用记录下来,等并发扫描结束之后,再将这些记录过的引用关系中的黑色对象为根,重新扫描一次。如CMS垃圾回收器。
  • 原始快照: 当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下来,在并发扫描结束之后,再将这些记录过的引用关系中的灰色对象为根,重新扫描一次。如G1垃圾回收器

2 垃圾回收算法

2.1 标记-清除算法

主要分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后,统一回收掉所有被标记的对象

存在的缺陷:

  1. 执行效率不稳定,随着标记对象数量的增长而降低
  2. 内存空间碎片化问题,标记-清除会产生大量不连续的内存碎片

2.2 标记-复制算法

将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。

当某一块内存快用完了,就将存活的对象复制到另一块内存上,然后把原来的内存空间直接清理即可。

相较于标记-清除算法的优点:

  1. 每次针对一个半区进行清理,不会产生碎片化的内存空间

存在的缺陷:

  1. 如果内存中多数对象都是存活对象,则会产生大量的内存间复制开销
  2. 将可用内存缩小为原来的一半,空间利用率低

现代Java虚拟机大多采用标记-复制算法回收新生代,因为新生代中只有极少数对象会存活。

2.3 标记-整理算法

首先标记出所有需要回收的对象;让所有存活对象向内存空间的一侧移动,最后清理掉边界以外的内存。

存在的缺陷:

  1. 移动存活对象并更新所有引用这些对象的地方是极为负重的操作,而且这种对象移动操作必须暂停用户程序才能进行(Stop The World)

3垃圾回收器

3.1 CMS收集器

Concurrent Mark Sweep(CMS) 收集器是一种以获取最短回收停顿时间(STW)为目标的收集器。该回收器基于标记-清除算法实现。

CMS收集器工作过程

  1. 初始标记(STW): 标记 GC Roots 能直接关联到的对象,速度很快
  2. 并发标记: 从 GC Roots 直接关联对象开始遍历整个对象图,不需要停顿用户线程
  3. 重新标记(STW): 修正并发标记,增量更新
  4. 并发清除: 清理掉所有消亡对象

CMS收集器由于使用并发-清除算法回收,会产生大量的内存空间碎片,可用暂时容忍;当内存空间的碎片化程度影响到对象分配时,再采用一次标记-整理算法,以获得规整的内存空间。

3.2 G1收集器

Grabage First(G1) 收集器开创了面向局部收集的设计思路和基于Region的内存布局形式。

基于 Region 的堆内存布局

  • 把连续的Java堆划分为多个大小相等的独立区域(Region),每一个 Region 都可用根据需分配给新生代Eden空间、Suvivor空间或者老年代空间。收集器对不同空间的 Region 块采用不同的策略处理。

  • Region 中还有一类特殊的 Humongous 区域(被视为老年代的一部分),专门用于存储大对象。G1认为只要大小超过一个Region块容量一半的对象就是大对象。每个 Region 大小为 1M ~ 32M,对于超过了整个 Region 容量的超级大对象会被存储到N个连续的Humongous Region块中。

  • G1虽然仍然保留了新生代和老年代的概念,但新生代和老年代的空间和位置不再是固定的,是一系列Region的集合。

G1收集器工作过程

  • 初始标记(STW): 标记 GC Roots 能直接关联到的对象
  • 并发标记: 从 GC Roots 直接关联对象开始遍历整个对象图,不需要停顿用户线程
  • 最终标记(STW): 处理并发标记阶段结束后仍然遗留下来的STAB(原始快照)记录
  • 筛选回收: 对各个Region块的回收价值和成本进行排序,根据期望的停顿时间指定回收计划,可用自由选择任意多个Region回收,然后将被回收的Region块中存活的对象复制到空的Region中

参考文章文章来源地址https://www.toymoban.com/news/detail-412443.html

  1. 深入理解Java虚拟机第3版

到了这里,关于Java GC基础知识的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java】图解 JVM 垃圾回收(一):GC 判断策略、引用类型、垃圾回收算法

    垃圾 是指运行程序中 没有任何引用指向的对象 ,需要被回收。 内存溢出 :经过垃圾回收之后,内存仍旧无法存储新创建的对象,内存不够溢出。 内存泄漏 :又叫 “ 存储泄漏 ”,对象不会再被程序使用了,但是 GC 又不能回收它们。例如:IO 流不适用了但是没有被 Close、

    2024年02月19日
    浏览(37)
  • JVM基础知识(内存区域划分,类加载,GC垃圾回收)

    目录 内存区域划分 JVM中的栈 JVM中的堆 程序计数器 方法区(元数据区) 给一段代码,某个变量在哪个区域上? 类加载 类加载时机 双亲委派模型 GC 垃圾回收机制 GC 实际工作过程 1.找到垃圾/判定垃圾 1.可达性分析(Java中的做法) 2.引用计数 2.清理垃圾 1.标记清除 2.复制算法 3.标记整

    2024年02月07日
    浏览(53)
  • [ XJTUSE ]JAVA语言基础知识——第一章 面向对象程序设计思想

    类描述了一组有相同 特性 (属性)和相同 行为 (方法)的对象,类和对象是面向对象思想的两个核心概念 · 人类是一种类,每一个具体的人则是这个类的对象 用面向对象程序来模拟真实世界 发现并创建类 发现类的特征 发现类的行为 在面向对象程序中,对象的特征由各种

    2023年04月13日
    浏览(45)
  • 对象存活判断

    对象存活判断 在堆里存放着几乎所有的 Java 对象实例,在 GC 执行垃圾回收之前,首先需要区分出内存中哪些是存活对象,哪些是已经死亡的对象。只有被标记为己经死亡的对象,GC 才会在执行垃圾回收时,释放掉其所占用的内存空间,因此这个过程我们可以称为垃圾标记阶

    2024年02月15日
    浏览(43)
  • 引用计数 vs 根可达算法:深入比较对象存活判定

    🔭 嗨,您好 👋 我是 vnjohn,在互联网企业担任 Java 开发,CSDN 优质创作者 📖 推荐专栏:Spring、MySQL、Nacos、Java,后续其他专栏会持续优化更新迭代 🌲文章所在专栏:JVM 🤔 我当前正在学习微服务领域、云原生领域、消息中间件等架构、原理知识 💬 向我询问任何您想要的

    2024年02月12日
    浏览(29)
  • Java 学习路线:基础知识、数据类型、条件语句、函数、循环、异常处理、数据结构、面向对象编程、包、文件和 API

    Java 是一种由 Sun Microsystems 于 1995 年首次发布的编程语言和计算平台。Java 是一种通用的、基于类的、面向对象的编程语言,旨在减少实现依赖性。它是一个应用程序开发的计算平台。Java 快速、安全、可靠,因此在笔记本电脑、数据中心、游戏机、科学超级计算机、手机等领

    2024年03月24日
    浏览(75)
  • 常用基础硬件知识 - 判断MOS管导通

    本文主要记录下基础的硬件知识,方便自己查阅。 后续有时间、遇到什么问题,就随时补充完善。 在产品硬件设计中,有时需要程序控制一些电源使能。 1.原理图已经标出了G极(gate)—栅极、S极(source)—源极、D极(drain)—漏极。 如果没有标出的话,引出两根线,像字母’F’就

    2024年02月04日
    浏览(62)
  • JVM 内存分哪几个区,如和判断一个对象是否存活

    JVM 内存分哪几个区,每个区的作用是什么 ? java 虚拟机主要分为以下一个区 : 方法区: 1. 有时候也成为 永久代 ,在该区内很少发生垃圾回收,但是并不代表不发生  GC ,在这里进行的  GC 主要是对方法区里的常量池和对类型的卸载 2. 方法区主要用来存储已被虚拟机加载的类

    2024年02月05日
    浏览(32)
  • 【python基础知识】python中怎么判断两个字符串是否相等

    目录 有哪些判断方法 1. == 运算符 2. is 运算符 有哪些特殊情况 1. 字符串中包含空格、换行符、制表符等特殊字符 2. 字符串编码格式的不同 3. 字符串对象的创建方式不同 注意事项 1. 避免使用is运算符进行字符串比较 2. 注意空格、换行符、制表符等特殊字符的影响 3. 注意字符

    2024年02月08日
    浏览(57)
  • C++类和对象基础知识详解

    1.一切皆是对象。如下图: ·女人是一个对象 ·鞋子是一个对象 ·包包是一个对象 ·衣服是一个对象 ·裤子是一个对象 ·手链是一个对象 … 这里人这个对象,由鞋子、包包、衣服、 裤子、手链等对象组成。 3.每个对象都有: a)数据(描述对象的属性) b)函数(行为操作代码

    2023年04月12日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包