`

GC原理及调优

    博客分类:
  • java
 
阅读更多

本文介绍 GC 基础原理和理论,GC 调优方法思路和方法,基于 Hotspot jdk1.8,学习之后你将了解如何对生产系统出现的 GC 问题进行排查解决。

内容主要如下:

  • GC 基础原理,涉及调优目标,GC 事件分类、JVM 内存分配策略、GC 日志分析等。
  • CMS 原理及调优。
  • GC 问题排查和解决思路。

GC 基础原理

GC 调优目标

大多数情况下对 Java 程序进行 GC 调优,主要关注两个目标:

  • 响应速度(Responsiveness):响应速度指程序或系统对一个请求的响应有多迅速。 比如,用户订单查询响应时间,对响应速度要求很高的系统,较大的停顿时间是不可接受的。调优的重点是在短的时间内快速响应。
  • 吞吐量(Throughput):吞吐量关注在一个特定时间段内应用系统的大工作量。 例如每小时批处理系统能完成的任务数量,在吞吐量方面优化的系统,较长的 GC 停顿时间也是可以接受的,因为高吞吐量应用更关心的是如何尽可能快地完成整个任务,不考虑快速响应用户请求。

GC 调优中,GC 导致的应用暂停时间影响系统响应速度,GC 处理线程的 CPU 使用率影响系统吞吐量。

GC 分代收集算法

现代的垃圾收集器基本都是采用分代收集算法,其主要思想: 将 Java 的堆内存逻辑上分成两块:新生代、老年代,针对不同存活周期、不同大小的对象采取不同的垃圾回收策略。

 
新生代(Young Generation)

 

新生代又叫年轻代,大多数对象在新生代中被创建,很多对象的生命周期很短。

每次新生代的垃圾回收(又称 Young GC、Minor GC、YGC)后只有少量对象存活,所以使用复制算法,只需少量的复制操作成本就可以完成回收。

新生代内又分三个区:一个 Eden 区,两个 Survivor 区(S0、S1,又称From Survivor、To Survivor,大部分对象在 Eden 区中生成。

当 Eden 区满时,还存活的对象将被复制到两个 Survivor 区(中的一个);当这个 Survivor 区满时,此区的存活且不满足晋升到老年代条件的对象将被复制到另外一个 Survivor 区。

对象每经历一次复制,年龄加 1,达到晋升年龄阈值后,转移到老年代。

老年代(Old Generation)

在新生代中经历了 N 次垃圾回收后仍然存活的对象,就会被放到老年代,该区域中对象存活率高。老年代的垃圾回收通常使用“标记-整理”算法。

GC 事件分类

根据垃圾收集回收的区域不同,垃圾收集主要分为:

  • Young GC
  • Old GC
  • Full GC
  • Mixed GC

①Young GC

新生代内存的垃圾收集事件称为 Young GC(又称 Minor GC,当 JVM 无法为新对象分配在新生代内存空间时总会触发 Young GC。

比如 Eden 区占满时,新对象分配频率越高,Young GC 的频率就越高。

Young GC 每次都会引起全线停顿(Stop-The-World,暂停所有的应用线程,停顿时间相对老年代 GC 造成的停顿,几乎可以忽略不计。

②Old GC 、Full GC、Mixed GC

Old GC:只清理老年代空间的 GC 事件,只有 CMS 的并发收集是这个模式。

Full GC:清理整个堆的 GC 事件,包括新生代、老年代、元空间等 。

Mixed GC:清理整个新生代以及部分老年代的 GC,只有 G1 有这个模式。

GC 日志分析

GC 日志是一个很重要的工具,它准确记录了每一次的 GC 的执行时间和执行结果,通过分析 GC 日志可以调优堆设置和 GC 设置,或者改进应用程序的对象分配模式。

开启的 JVM 启动参数如下:

-verbose:gc-XX:+PrintGCDetails-XX:+PrintGCDateStamps-XX:+PrintGCTimeStamps

 

常见的 Young GC、Full GC 日志含义如下:

 


 
免费的 GC 日志图形分析工具推荐下面 2 个:

  • GCViewer,下载 jar 包直接运行 。
  • gceasy,Web 工具,上传 GC 日志在线使用。

内存分配策略

Java 提供的自动内存管理,可以归结为解决了对象的内存分配和回收的问题。

前面已经介绍了内存回收,下面介绍几条普遍的内存分配策略:

①对象优先在 Eden 区分配:大多数情况下,对象在先新生代 Eden 区中分配。当 Eden 区没有足够空间进行分配时,虚拟机将发起一次 Young GC。

②大对象之间进入老年代:JVM 提供了一个对象大小阈值参数(-XX:PretenureSizeThreshold,默认值为 0,代表不管多大都是先在 Eden 中分配内存

大于参数设置的阈值值的对象直接在老年代分配,这样可以避免对象在 Eden 及两个 Survivor 直接发生大内存复制。

③长期存活的对象将进入老年代:对象每经历一次垃圾回收,且没被回收掉,它的年龄就增加 1,大于年龄阈值参数(-XX:MaxTenuringThreshold,默认 15的对象,将晋升到老年代中。

④空间分配担保:当进行 Young GC 之前,JVM 需要预估:老年代是否能够容纳 Young GC 后新生代晋升到老年代的存活对象,以确定是否需要提前触发 GC 回收老年代空间,基于空间分配担保策略来计算。

continueSize,老年代大可用连续空间:

 
Young GC 之后如果成功(Young GC 后晋升对象能放入老年代,则代表担保成功,不用再进行 Full GC,提高性能。

如果失败,则会出现“promotion failed”错误,代表担保失败,需要进行 Full GC。

⑤动态年龄判定:新生代对象的年龄可能没达到阈值(MaxTenuringThreshold 参数指定)就晋升老年代。

如果 Young GC 之后,新生代存活对象达到相同年龄所有对象大小的总和大于任意 Survivor 空间(S0+S1空间)的一半,此时 S0 或者 S1 区即将容纳不了存活的新生代对象。

年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到 MaxTenuringThreshold 中要求的年龄。

另外,如果 Young GC 后 S0 或 S1 区不足以容纳:未达到晋升老年代条件的新生代存活对象,会导致这些存活对象直接进入老年代,需要尽量避免。

CMS 原理及调优

 

名词解释

可达性分析算法:用于判断对象是否存活,基本思想是通过一系列称为“GC Root”的对象作为起点(常见的 GC Root 有系统类加载器、栈中的对象、处于激活状态的线程等),基于对象引用关系,从 GC Roots 开始向下搜索,所走过的路径称为引用链,当一个对象到 GC Root 没有引用链相连,证明对象不再存活。

Stop The World:GC 过程中分析对象引用关系,为了保障分析结果的准确性,需要通过停顿所有 Java 执行线程,保证引用关系不再动态变化,该停顿事件称为 Stop The World(STW

Safepoint:代码执行过程中的一些特殊位置,当线程执行到这些位置的时候,说明虚拟机当前的状态是安全的,如果有需要 GC,线程可以在这个位置暂停。

HotSpot 采用主动中断的方式,让执行线程在运行期轮询是否需要暂停的标志,若需要则中断挂起。

 

CMS 简介

CMS(Concurrent Mark and Sweep 并发-标记-清除,是一款基于并发、使用标记清除算法的垃圾回收算法,只针对老年代进行垃圾回收。

CMS 收集器工作时,尽可能让 GC 线程和用户线程并发执行,以达到降低 STW 时间的目的。

通过以下命令行参数,启用 CMS 垃圾收集器:

-XX:+UseConcMarkSweepGC

值得补充的是,下面介绍到的 CMS GC 是指老年代的 GC,而 Full GC 指的是整个堆的 GC 事件,包括新生代、老年代、元空间等,两者有所区分。

新生代垃圾回收

能与 CMS 搭配使用的新生代垃圾收集器有 Serial 收集器和 ParNew 收集器。

 

这 2 个收集器都采用标记复制算法,都会触发 STW 事件,停止所有的应用线程。不同之处在于,Serial 是单线程执行,ParNew 是多线程执行。

 

 

cms运行流程图如下



 


 
老年代垃圾回收

 


 
CMS GC 以获取小停顿时间为目的,尽可能减少 STW 时间,可以分为 7 个阶段:

阶段 1:初始标记(Initial Mark)

 
此阶段的目标是标记老年代中所有存活的对象, 包括 GC Root 的直接引用, 以及由新生代中存活对象所引用的对象,触发第一次 STW 事件。

这个过程是支持多线程的(JDK7 之前单线程,JDK8 之后并行,可通过参数 CMSParallelInitialMarkEnabled 调整)。

 

阶段 2:并发标记(Concurrent Mark

 
此阶段 GC 线程和应用线程并发执行,遍历阶段 1 初始标记出来的存活对象,然后继续递归标记这些对象可达的对象。

 

阶段 3:并发预清理(Concurrent Preclean

 
此阶段 GC 线程和应用线程也是并发执行,因为阶段 2 是与应用线程并发执行,可能有些引用关系已经发生改变。

通过卡片标记(Card Marking,提前把老年代空间逻辑划分为相等大小的区域(Card

如果引用关系发生改变,JVM 会将发生改变的区域标记为“脏区”(Dirty Card,然后在本阶段,这些脏区会被找出来,刷新引用关系,清除“脏区”标记。

 

阶段 4:并发可取消的预清理(Concurrent Abortable Preclean

此阶段也不停止应用线程。本阶段尝试在 STW 的最终标记阶段(Final Remark之前尽可能地多做一些工作,以减少应用暂停时间。

在该阶段不断循环处理:标记老年代的可达对象、扫描处理 Dirty Card 区域中的对象,循环的终止条件有:

 

  • 达到循环次数
  • 达到循环执行时间阈值
  • 新生代内存使用率达到阈值

阶段 5:最终标记(Final Remark

这是 GC 事件中第二次(也是最后一次STW 阶段,目标是完成老年代中所有存活对象的标记。

在此阶段执行:

  • 遍历新生代对象,重新标记
  • 根据 GC Roots,重新标记
  • 遍历老年代的 Dirty Card,重新标记

阶段 6:并发清除(Concurrent Sweep

此阶段与应用程序并发执行,不需要 STW 停顿,根据标记结果清除垃圾对象。

 

阶段 7:并发重置(Concurrent Reset

 

此阶段与应用程序并发执行,重置 CMS 算法相关的内部数据, 为下一次 GC 循环做准备。

 

CMS 常见问题

①最终标记阶段停顿时间过长问题

CMS 的 GC 停顿时间约 80% 都在最终标记阶段(Final Remark,若该阶段停顿时间过长,常见原因是新生代对老年代的无效引用,在上一阶段的并发可取消预清理阶段中,执行阈值时间内未完成循环,来不及触发 Young GC,清理这些无效引用。

通过添加参数:-XX:+CMSScavengeBeforeRemark。

在执行最终操作之前先触发 Young GC,从而减少新生代对老年代的无效引用,降低最终标记阶段的停顿。

但如果在上个阶段(并发可取消的预清理已触发 Young GC,也会重复触发 Young GC。

 

②并发模式失败(concurrent mode failure)&晋升失败(promotion failed)问题。

 
并发模式失败:当 CMS 在执行回收时,新生代发生垃圾回收,同时老年代又没有足够的空间容纳晋升的对象时,CMS 垃圾回收就会退化成单线程的 Full GC。所有的应用线程都会被暂停,老年代中所有的无效对象都被回收。

 
晋升失败:当新生代发生垃圾回收,老年代有足够的空间可以容纳晋升的对象,但是由于空闲空间的碎片化,导致晋升失败,此时会触发单线程且带压缩动作的 Full GC。

并发模式失败和晋升失败都会导致长时间的停顿,常见解决思路如下:

  • 降低触发 CMS GC 的阈值。 即参数 -XX:CMSInitiatingOccupancyFraction 的值,让 CMS GC 尽早执行,以保证有足够的空间。
  • 增加 CMS 线程数,即参数 -XX:ConcGCThreads。
  • 增大老年代空间。
  • 让对象尽量在新生代回收,避免进入老年代。

③内存碎片问题

通常 CMS 的 GC 过程基于标记清除算法,不带压缩动作,导致越来越多的内存碎片需要压缩。

常见以下场景会触发内存碎片压缩:

  • 新生代 Young GC 出现新生代晋升担保失败(promotion failed))
  • 程序主动执行System.gc

可通过参数 CMSFullGCsBeforeCompaction 的值,设置多少次 Full GC 触发一次压缩。

默认值为 0,代表每次进入 Full GC 都会触发压缩,带压缩动作的算法为上面提到的单线程 Serial Old 算法,暂停时间(STW时间挺长,需要尽可能减少压缩时间。

 

调优方法与思路

如何分析系统 JVM GC 运行状况及合理优化?

GC 优化的核心思路在于:尽可能让对象在新生代中分配和回收,尽量避免过多对象进入老年代,导致对老年代频繁进行垃圾回收,同时给系统足够的内存减少新生代垃圾回收次数,进行系统分析和优化也是围绕着这个思路展开。

分析系统的运行状况

分析系统的运行状况:

  • 系统每秒请求数、每个请求创建多少对象,占用多少内存。
  • Young GC 触发频率、对象进入老年代的速率。
  • 老年代占用内存、Full GC 触发频率、Full GC 触发的原因、长时间 Full GC 的原因。

 

常用工具如下:

jstat:JVM自带命令行工具,可用于统计内存分配速率、GC 次数,GC 耗时。

常用命令格式:

jstat -gc <pid><统计间隔时间><统计次数>

 

输出返回值代表含义如下:


 

  • 大小: 3.7 KB
  • 大小: 96.2 KB
  • 大小: 112.5 KB
  • 大小: 38.1 KB
  • 大小: 4.9 KB
  • 大小: 7.6 KB
  • 大小: 27.1 KB
  • 大小: 28.3 KB
  • 大小: 57.6 KB
  • 大小: 7.8 KB
  • 大小: 6.5 KB
  • 大小: 41 KB
  • 大小: 295.2 KB
分享到:
评论

相关推荐

    JVM、GC详解及调优_jvm_JVM、GC详解及调优_

    总之,《JVM、GC详解及调优》这份资料将带你深入了解JVM的工作原理,帮助你掌握GC的运作机制,并提供实用的调优技巧,提升Java应用程序的性能。通过持续学习和实践,你将能够更好地管理和优化你的Java应用。

    jvm和gc详解及调优

    《JVM和GC详解及调优》是一本深入解析Java虚拟机(JVM)和垃圾收集(Garbage Collection,简称GC)的专业书籍,对于Java开发者来说,是进阶提升的必备资料。书中详尽地阐述了JVM的工作原理,以及如何进行有效的性能...

    JVM、GC详解及调优

    总结,理解和掌握JVM的工作原理以及GC机制,对于优化Java应用性能至关重要。通过细致的调优,可以有效减少垃圾收集的开销,提升系统的稳定性和响应速度。同时,持续监控和分析JVM运行状态,能帮助我们及时发现并解决...

    JVM、GC详解及调优.pdf

    本文档详细讲解了JVM(Java Visual Mathine)的方方面面,首先由java的特性来描绘JVM的大致应用,再详细阐释了 JVM 的原理及内存管理机制和调优,讲述了与JVM密切相关的 Java GC 机制,最后对 JVM 调优进行了总结。...

    Java_GC垃圾回收调优指南

    本指南旨在帮助开发者深入理解Java GC的工作原理,并提供一系列调优策略与实例,以确保Java应用能够高效稳定地运行。 #### Java GC基础知识 垃圾回收是一种自动化的内存管理机制,它负责回收不再使用的对象所占用...

    jvm原理与调优

    该文档是关于java虚拟机的原理,描述及调优视频,其中,详细讲述了jvm的运行机制,类装载器,GC算法,性能监控工具,堆,锁等内容。

    JVM GC原理, heapsize调优

    在JVM GC原理和heapsize调优的学习和实践过程中,需要理解多个关键概念和操作步骤,下面详细展开: 1. 垃圾回收机制的理解 在Java中,当对象不再被引用时,它们应该被垃圾回收器回收。GC机制基于几个关键概念工作,...

    JVM_GC调优

    ### JVM_GC调优详解 #### 一、JVM体系结构概览 Java虚拟机(JVM)作为Java程序的运行环境,其内部结构复杂且高效。为了更好地理解JVM_GC调优,...同时,掌握JVM内存模型和垃圾回收器的工作原理也是进行有效调优的基础。

    JAVA应用JVM原理及参数调优深入讲解视频.rar

    本课程深入讲解了JVM的工作原理以及如何进行参数调优,旨在帮助开发者提升应用程序的性能和稳定性。 首先,我们来探讨JVM的基本原理。JVM是一个抽象的计算机,它具有硬件系统的许多特性,如内存管理、指令集等。当...

    JVM垃圾回收机制与GC性能调优

    本文主要探讨JVM堆内存的结构和GC的工作原理,以及如何进行性能调优。 JVM堆是Java应用程序的主要内存区域,用于存储所有类实例和数组。它分为三个主要区域:新域(Young Generation)、旧域(Old Generation)和...

    JVM内存管理及GC原理调优实战

    在去做这项工作前就必须去了解JVM是怎么去管理内存的,GC是怎么完成的。 二、标记算法 垃圾回收是对已经分配出去的但又不再使用的内存进行回收,以便能够再次分配。JVM主要是对堆空间那些死亡对象所占据的空间进行...

    从源码的角度探索Java中间件-Tomcat & Jetty的深度反汇编

    JVMGC原理及调优的基本思路: 如何监控Tomcat的性能? Tomcat线程池和I/O的并发调优 Tomcat的内存溢出原因分析及调优 Tomcat拒绝连接原因分析及网络优化 Tomcat进程占用CPU过高怎么办 谈谈Jetty性能调优的思路 热点...

    jvm原理机器调优-jvm.zip

    JVM原理和调优是每个Java开发人员必须掌握的关键技能,这涉及到内存管理、垃圾收集、性能优化等多个方面。在深入理解JVM的工作机制后,我们可以更好地调整和优化应用程序,提升系统的性能和稳定性。 一、JVM结构与...

    JVM体系结构与GC调优

    **2.2 GC工作原理**:GC通过一系列算法找到并回收这些垃圾对象,主要分为标记-清除、复制、标记-整理和分代收集等策略。 - **年轻代(Young Generation)**:新生代,分为Eden区和两个Survivor区(From和To)。...

    JVM调优,GC算法汇总

    GC的工作原理可以分为几个主要阶段:标记、扫描、复制和压缩。这些步骤旨在识别并清理无用对象,优化内存布局,以及减少内存碎片。在JVM中,有多种不同的GC算法,每种都有其特定的应用场景和优缺点。 1. **串行GC...

    用于测试jvm gc调优-share-jvm-gc.zip

    首先,我们需要理解JVM GC的基本原理。垃圾收集器的主要任务是识别并回收不再使用的对象所占用的内存空间,以防止内存泄漏。Java提供了多种不同的垃圾收集器,如Serial、Parallel、CMS(Concurrent Mark Sweep)、G1...

    java性能调优及原理介绍.pdf

    Java性能调优主要聚焦在JVM的优化,其中包括内存模型的理解、垃圾收集(GC)机制以及如何处理常见的Out of Memory (OOM)异常。首先,我们要理解JVM的内存模型,这是进行性能调优的基础。 JVM内存模型由堆、栈、方法...

    java gc调优

    在《浅谈JVM内存管理》的PPT中,可能包含了对上述概念的详细讲解,包括JVM内存模型的解析、GC算法的工作原理、如何配置和调整GC参数,以及通过实例分析GC调优的具体步骤。通过学习这个PPT,开发者可以深入理解JVM...

    JVM原理与调优实战下载即用

    设置生代带垃圾对象最大年龄,进量不要有大量连续内存空间的java对象,因为会直接到老年代,内存不够就会执行GC 开发大型 Java 应用程序的过程中难免遇到内存泄露、性能瓶颈等问题,比如文件、网络、数据库的连接未...

    06.JVM原理讲解和调优.pdf

    JVM 原理讲解和调优 JVM(Java Virtual Machine,Java 虚拟机)是 Java 语言的核心组件,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM 的主要功能是将 Java 字节码转换为...

Global site tag (gtag.js) - Google Analytics