热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

深入浅析JVM垃圾回收机制与收集器概述

本文基于《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》的阅读心得进行整理,详细探讨了JVM的垃圾回收机制及其各类收集器的特点与应用场景。通过分析不同垃圾收集器的工作原理和性能表现,帮助读者深入了解JVM内存管理的核心技术,为优化Java应用程序提供实用指导。

作品标明出处:本文是对《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》阅读后的整理,有兴趣的同学可购买正版进行学习!


1.查看JVM默认垃圾收集器

java -XX:+PrintCommandLineFlags -version

上图中的 -XX:+UseParallelGC就是我们默认使用的收集器,新生代使用的是Parallel Scanvenge收集器,老年代使用的是Serial Old


2.JVM垃圾收集器常用参数

 


3.垃圾收集器

 如果两个收集器之间存在连线,就说明它们可以搭配使用 ,图中收集器所处的区域,则表示它是属于新生代收集器抑或是老年代收集器


  •  Serial收集器

新生代收集器,低延迟

单线程收集器:不仅仅是说明它只会使用一个处理器或一条收集线程去完成垃圾收集工作,更重要的是强调在它进行垃圾收集时,必须暂停其他所有工作线程,直到它收集结束,Stop The World!


  •  ParNew收集器

新生代收集器

是Serial收集器的多线程并行版本。

只有它能和CMS收集器搭配使用。

ParNew收集器是激活CMS后(使用-XX:+UseConcMarkSweepGC选项)的默认新生代收集器,也可以使用-XX:+/-UseParNewGC选项来强制指定或者禁用它。


  •  Parallel Scanvenge收集器

新生代收集器,标记--复制算法

和ParNew收集器非常相似,目标是达到一个可控制的吞吐量

 参数 -XX:+UseAdaptiveSizePolicy,垃圾收集的自适应调节策略,不需要人工指定新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRatio)、晋升老年代对象大小(-XX:PretenureSizeThreshold)等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量


  • Serial Old收集器

老年代单线程收集器,标记--整理算法

两种用途:

        1、在JDK 5以及之前的版本中与Parallel Scavenge收集器搭配使用 

        2、作为CMS收集器发生失败时的后备预案,在并发收集发生Concurrent Mode Failure时使用

.


  •  Parallel Old收集器

老年代多线程收集器,标记--整理算法

Parallel Scavenge + Parallel Old收集器搭配使用,吞吐量优先


  •  CMS收集器(Concurrent Mark Sweep)

老年代多线程收集器,标记--清除算法(收集结束可能会导致大量空间碎片,触发Full GC)

并发收集、低延迟,“并发低停顿收集器”(Concurrent Low Pause Collector)

整个过程分为四个步骤:

        1、初始标记(CMS initial mark)
        2、并发标记(CMS concurrent mark)
        3、重新标记(CMS remark)
        4、并发清除(CMS concurrent sweep)

 JDK5默认启动阈值为老年代使用了 68%,

JDK6时默认阈值提升至92%,此时可能导致CMS运行期间预留的内存无法满足程序分配新对象的需要,就会出现一次“并发失败”(Concurrent Mode Failure),这时候虚拟机将不得不启动后备预案:冻结用户线程的执行,临时启用Serial Old收集器来重新进行老年代的垃圾收集


  • G1(Garbage First)收集器

面向整个堆空间多线程收集器,标记--整理算法,每个Region又是基于标记--复制算法

低延迟、

JDK9以后默认垃圾收集器

面向局部收集、基于Region内存布局

面向堆内存任何部分来组成回收集,衡量标准为哪块内存中存放的垃圾最多,会后收益最大,这就是G1收集器的Mixed GC模式

G1把连续的Java堆划分为多个大小相等的独立区域Region,每个Region都可以根据需要,扮演新生代的Eden空间、Survivor空间,或者老年代空间;Region中还有一类特殊的Humongous区域,专门用来存储大对象。G1认为只要大小超过了一个Region容量一半的对象即可判定为大对象

每个Region大小可以通过参数-XX:G1HeapRegionSize设定,取值范围为1MB~32MB,且应为2的N次幂

而对于那些超过了整个Region容量的超级大对象,将会被存放在N个连续的Humongous Region之中,G1的大多数行为都把Humongous Region作为老年代的一部分来进行看待

 Region里面存在的跨Region引用对象如何解决?

 答:使用记忆集避免全堆作为GC Roots扫描,每个Region都维护有自己的记忆集,这些记忆集会记录下别的Region指向自己的指针,并标记这些指针分别在哪些卡页的范围之内。

由于Region数量比传统收集器的分代数量明显要多得多,因此G1收集器要比其他的传统垃圾收集器有着更高的内存占用负担。根据经验,G1至少要耗费大约相当于Java堆容量10%至20%的额外内存来维持收集器工作

G1收集器的四个步骤:

        1、初始标记(Initial Marking)

        2、并发标记(Concurrent Marking)

        3、最终标记(Final Marking)

        4、筛选回收(Live Data Counting and Evacuation)


  •  Shenandoah收集器

低延迟、并发收集,标记--整理算法

也是基于Region的堆内存布局,同样有着用于存放大对象的Humongous Region,默认的回收策略也同样是优先处理回收价值最大的Region

Shenandoah(目前)是默认不使用分代收集,不会有专门的新生代Region或者老年代Region的存在,没有实现分代

Shenandoah摒弃了在G1中耗费大量内存和计算资源去维护的记忆集,改用名为“连接矩阵”(ConnectionMatrix)的全局数据结构来记录跨Region的引用关系,降低了处理跨代指针时的记忆集维护消耗,也降低了伪共享问题的发生概率

Shenandoah收集器的工作过程大致可以划分为以下九个阶段:

        1、初始标记(Initial Marking)

        2、并发标记(Concurrent Marking)

        3、最终标记(Final Marking)

        4、并发清理(Concurrent Cleanup)

        5、并发回收(Concurrent Evacuation)

        6、初始引用更新(Initial Update Reference)

        7、并发引用更新(Concurrent Update Reference)

        8、最终引用更新(Final Update Reference)

        9、并发清理(Concurrent Cleanup)


  • ZGC

低延迟垃圾收集器,基于Region内存布局,并发标记-整理算法

ZGC的Region具有动态性——动态创建和销毁

在x64硬件平台下,ZGC的Region可以具有如图3-19所示的大、中、小三类容量:
        1、小型Region(Small Region):容量固定为2MB,用于放置小于256KB的小对象。
        2、中型Region(Medium Region):容量固定为32MB,用于放置大于等于256KB但小于4MB的对象。
        3、大型Region(Large Region):容量不固定,可以动态变化,但必须为2MB的整数倍,用于放置4MB或以上的大对象。每个大型Region中只会存放一个大对象

 ZGC收集器的运作过程:

        1、并发标记(Concurrent Mark)

        2、并发预备重分配(Concurrent Prepare for Relocate)

        3、并发重分配(Concurrent Relocate)

        4、并发重映射(Concurrent Remap)



推荐阅读
  • 深入解析JVM垃圾收集器
    本文基于《深入理解Java虚拟机:JVM高级特性与最佳实践》第二版,详细探讨了JVM中不同类型的垃圾收集器及其工作原理。通过介绍各种垃圾收集器的特性和应用场景,帮助读者更好地理解和优化JVM内存管理。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 深入理解Java中的volatile、内存屏障与CPU指令
    本文详细探讨了Java中volatile关键字的作用机制,以及其与内存屏障和CPU指令之间的关系。通过具体示例和专业解析,帮助读者更好地理解多线程编程中的同步问题。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • 并发编程:深入理解设计原理与优化
    本文探讨了并发编程中的关键设计原则,特别是Java内存模型(JMM)的happens-before规则及其对多线程编程的影响。文章详细介绍了DCL双重检查锁定模式的问题及解决方案,并总结了不同处理器和内存模型之间的关系,旨在为程序员提供更深入的理解和最佳实践。 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • FinOps 与 Serverless 的结合:破解云成本难题
    本文探讨了如何通过 FinOps 实践优化 Serverless 应用的成本管理,提出了首个 Serverless 函数总成本估计模型,并分享了多种有效的成本优化策略。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 本文深入探讨了 Java 中的 Serializable 接口,解释了其实现机制、用途及注意事项,帮助开发者更好地理解和使用序列化功能。 ... [详细]
  • 本文深入探讨了Linux系统中网卡绑定(bonding)的七种工作模式。网卡绑定技术通过将多个物理网卡组合成一个逻辑网卡,实现网络冗余、带宽聚合和负载均衡,在生产环境中广泛应用。文章详细介绍了每种模式的特点、适用场景及配置方法。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • 本文介绍了如何通过 Maven 依赖引入 SQLiteJDBC 和 HikariCP 包,从而在 Java 应用中高效地连接和操作 SQLite 数据库。文章提供了详细的代码示例,并解释了每个步骤的实现细节。 ... [详细]
  • 实体映射最强工具类:MapStruct真香 ... [详细]
  • 本文探讨了在Java多线程环境下,如何确保具有相同key值的线程能够互斥执行并按顺序输出结果。通过优化代码结构和使用线程安全的数据结构,我们解决了线程同步问题,并实现了预期的并发行为。 ... [详细]
author-avatar
青岛新侨妙妙
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有