Java虚拟机-垃圾回收器

简介: Java虚拟机-垃圾回收器

 image.gif编辑

一、如何查看垃圾回收器

查看JVM的默认垃圾回收器,可以看出JDK8中UseParallelGC即Parallel Scavenge+Serial Old

java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=266359616 
-XX:MaxHeapSize=4261753856 
-XX:+PrintCommandLineFlags 
-XX:+UseCompressedClassPointers 
-XX:+UseCompressedOops 
-XX:-UseLargePagesIndividualAllocation 
-XX:+UseParallelGC
java version "1.8.0_211"
Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)

image.gif

查看垃圾回收器详细信息

java -XX:+PrintGCDetails -version
java version "1.8.0_211"
Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)
Heap
 PSYoungGen      total 76288K, used 3932K [0x000000076b500000, 0x0000000770a00000, 0x00000007c0000000)
  eden space 65536K, 6% used [0x000000076b500000,0x000000076b8d7240,0x000000076f500000)
  from space 10752K, 0% used [0x000000076ff80000,0x000000076ff80000,0x0000000770a00000)
  to   space 10752K, 0% used [0x000000076f500000,0x000000076f500000,0x000000076ff80000)
 ParOldGen       total 175104K, used 0K [0x00000006c1e00000, 0x00000006cc900000, 0x000000076b500000)
  object space 175104K, 0% used [0x00000006c1e00000,0x00000006c1e00000,0x00000006cc900000)
 Metaspace       used 2366K, capacity 4480K, committed 4480K, reserved 1056768K
  class space    used 255K, capacity 384K, committed 384K, reserved 1048576K

image.gif

二、常见垃圾回收器介绍

1.Serial

使用场景主要为客户端。是最基本,发展最悠久的单线程垃圾收集器,是JDK1.3.1前HotSpot新生代收集的唯一选择。分为新生代和老年代两个,分别采用了复制算法和标记-整理算法。

image.gif编辑

1)特点

    • 针对新生代;
    • 采用复制算法;
    • 单线程收集;
    • 进行垃圾收集时,必须暂停所有工作线程,直到完成,即会"Stop The World"。

    2)应用场景

      • 依然是HotSpot在Client模式下默认的新生代收集器;
      • 简单高效(与其他收集器的单线程相比);
      • 对于限定单核CPU的环境,没有线程开销,可以获得最高的单线程收集效率;
      • 在用户的桌面应用场景中,可用内存一般不大(几十M至一两百M),可以在较短时间内完成垃圾收集(几十MS至一百多MS),只要不频繁发生,可以接受。

      3)使用方式

      "-XX:+UseSerialGC":添加该参数来显式使用串行垃圾收集器

      2.ParNew

      ParNew垃圾收集器是Serial收集器的多线程版本。

      image.gif编辑

      1)特点

        • 除了多线程外,其余的行为、特点和Serial收集器一样,如Serial收集器可用控制参数、收集算法、Stop The World、内存分配规则、回收策略等;
        • 两个收集器共用了不少代码。

        2)应用场景

          • 在Server模式下,ParNew收集器是一个非常重要的收集器,因为除Serial外,目前只有它能与CMS收集器配合工作;
          • 但在单个CPU环境中,不会比Serail收集器有更好的效果,因为存在线程交互开销。

          3)使用方式

          -XX:+UseConcMarkSweepGC:指定使用CMS后,会默认使用ParNew作为新生代收集器;

          -XX:+UseParNewGC:强制指定使用ParNew;

          -XX:ParallelGCThreads:指定垃圾收集的线程数量,ParNew默认开启的收集线程与CPU的数量相同;

          3.Parallel

          Parallel Scavenge 收集器是一个新生代收集器,采用复制算法,并且是多线程收集器;与ParNew最大的不同,它关注的是垃圾回收的吞吐量(Throughput)。

          Parallel Old 收集器是Parallel Scavenge 收集器的老年代版本,使用多线程和“标记-整理”算法。

          JDK7和8环境下,默认使用 Parallel Scavenge(新生代)+ Serial Old(老年代)。

          image.gif编辑

          1)特点

            • 在注重吞吐量以及CPU资源敏感的场合,可以优先考虑Parallel Scavenge 加 Parallel Old 收集器。
            • 吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)

            2)应用场景

              • 主要适合在后台运算而不需要太多交互的任务:
              • 停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验,而高吞吐量则可以高效的利用CPU时间,尽快完成程序的运算任务。

              3)使用方式

              -XX:+UseParallelGC :使用Parallel作为垃圾收集器;

              -XX:MaxGCPauseMillis:控制最大垃圾收集停顿时间

              -XX:GCTimeRatio:设置吞吐量大小

              4.CMS

              CMS,Concurrent Mark Sweep,同样是老年代的收集器。它关注的是垃圾回收最短的停顿时间(低停顿),在老年代并不频繁GC的场景下,是比较适用的。

              1)整体流程

                • 初始标记(initial mark),单线程执行,需要“Stop The World”,但仅仅把GC Roots的直接关联可达的对象给标记一下,由于直接关联对象比较小,所以这里的速度非常快。
                • 并发标记(concurrent mark),对于初始标记过程所标记的初始标记对象,进行并发追踪标记,此时其他线程仍可以继续工作。此处时间较长,但不停顿。
                • 重新标记(remark),在并发标记的过程中,由于可能还会产生新的垃圾,所以此时需要重新标记新产生的垃圾。此处执行并行标记,与用户线程不并发,所以依然是“Stop The World”,时间比初始时间要长一点。
                • 并发清除(concurrent sweep),并发清除之前所标记的垃圾。其他用户线程仍可以工作,不需要停顿。

                image.gif编辑

                2)特点

                  • 由于最耗费时间的并发标记与并发清除阶段都不需要暂停工作,所以整体的回收是低停顿的;
                  • Mark Sweep算法会导致内存碎片比较多;
                  • CMS的并发能力依赖于CPU资源,所以在CPU数少和CPU资源紧张的情况下,性能较差;
                  • 并发清除阶段,用户线程依然在运行,所以依然会产生新的垃圾,此阶段的垃圾并不会再本次GC中回收,而放到下次。所以GC不能等待内存耗尽的时候才进行GC,这样的话会导致并发清除的时候,用户线程可以了利用的空间不足。所以这里会浪费一些内存空间给用户线程预留。

                  3)应用场景

                    • CMS只会回收老年代和永久带(1.8开始为元数据区,需要设置CMSClassUnloadingEnabled),不会收集年轻带;
                    • CMS是一种预处理垃圾回收器,它不能等到old内存用尽时回收,需要在内存用尽前,完成回收操作,否则会导致并发回收失败;所以CMS垃圾回收器开始执行回收操作,有一个触发阈值,默认是老年代或永久带达到92%。

                    4)使用方式

                    -XX:+UseConcMarkSweepGC 激活CMS收集器

                    -XX:ConcGCThreads 设置CMS线程的数量

                    -XX:+UseCMSInitiatingOccupancyOnly 只根据老年代使用比例来决定是否进行CMS

                    -XX:CMSInitiatingOccupancyFraction 设置触发CMS老年代回收的内存使用率占比

                    -XX:+CMSParallelRemarkEnabled 并行运行最终标记阶段,加快最终标记的速度

                    -XX:+UseCMSCompactAtFullCollection 每次触发CMS Full GC的时候都整理一次碎片

                    -XX:CMSFullGCsBeforeCompaction=* 经过几次CMS Full GC的时候整理一次碎片

                    -XX:+CMSClassUnloadingEnabled 让CMS可以收集永久带,默认不会收集

                    -XX:+CMSScavengeBeforeRemark 最终标记之前强制进行一个Minor GC

                    -XX:+ExplicitGCInvokesConcurrent 当调用System.gc()的时候,执行并行gc,只有在CMS或者G1下该参数才有效

                    5.G1

                    G1,Garbage First,在JDK 1.7版本正式启用,是当时最前沿的垃圾收集器。G1可以说是CMS的终极改进版,解决了CMS内存碎片、更多的内存空间登问题。虽然流程与CMS比较相似,但底层的原理已是完全不同。

                    JDK1.9 默认垃圾收集器G1。

                    1)特点

                      • 高效益优先。G1会预测垃圾回收的停顿时间,原理是计算老年代对象的效益率,优先回收最大效益的对象。
                      • 堆内存结构的不同。以前的收集器分代是划分新生代、老年代、持久代等。G1则是把内存分为多个大小相同的区域Region,每个Region拥有各自的分代属性,但这些分代不需要连续。

                      下面是老式收集器和G1收集器的分代对比:

                      image.gif编辑

                      image.gif编辑

                        • 这样的分区可以有效避免内存碎片化问题。但会造成分代内存不连续,导致在GC搜索垃圾对象的时候需要全盘扫描找出引用内存所在。所以G1对于每个Region都维护一个Remembered Set,用于记录对象引用的情况。当GC发生的时候根据Remembered Set的引用情况去搜索。

                        2)整体流程

                          • 初始标记(initial mark),标记了从GC Root开始直接关联可达的对象。STW(Stop the World)执行。
                          • 并发标记(concurrent marking),并发标记初始标记的对象,此时用户线程依然可以执行。
                          • 最终标记(Remark),STW,标记再并发标记过程中产生的垃圾。
                          • 筛选回收(Live Data Counting And Evacuation),评估标记垃圾,根据GC模式回收垃圾。STW执行。

                          image.gif编辑

                          3)应用场景

                            • G1是一款面向服务端应用的垃圾收集器。
                            • 大堆(6左右,>=)运行,低GC延迟(<=0.5s)要求,
                            • GC频繁;收集或者压缩时间长;收集对象年龄差异大。

                            4)使用方式

                            -XX:+UseG1GC

                            不要设置年轻代大小 --Xmn;G1自动调整

                            XX:MaxGCPauseMillis:设置为能够满足90%请求的时间值。

                            6.ZGC

                            在JDK 11当中,加入了实验性质的ZGC。它的回收耗时平均不到2毫秒。它是一款低停顿高并发的收集器。ZGC几乎在所有地方并发执行的,除了初始标记的是STW的。所以停顿时间几乎就耗费在初始标记上,这部分的实际是非常少的。

                            image.gif编辑

                            1)特点

                              • 着色指针Colored Pointer。ZGC利用指针的64位中的几位表示Finalizable、Remapped、Marked1、Marked0(ZGC仅支持64位平台),以标记该指向内存的存储状态。相当于在对象的指针上标注了对象的信息。在这个被指向的内存发生变化的时候(内存在Compact被移动时),颜色就会发生变化。
                              • 读屏障Load Barrier 。由于着色指针的存在,在程序运行时访问对象的时候,可以轻易知道对象在内存的存储状态(通过指针访问对象),若请求读的内存在被着色了。那么则会触发读屏障。读屏障会更新指针再返回结果,此过程有一定的耗费,从而达到与用户线程并发的效果。

                              2)整体流程

                              与标记对象的传统算法相比,ZGC在指针上做标记,在访问指针时加入Load Barrier(读屏障),比如当对象正被GC移动,指针上的颜色就会不对,这个屏障就会先把指针更新为有效地址再返回,也就是,永远只有单个对象读取时有概率被减速,而不存在为了保持应用与GC一致而粗暴整体的Stop The World。

                              3)性能提升

                              ZGC的吞吐量与Parallel GC(优化吞吐量)大致相当,但平均暂停时间为1ms,最长为4ms。 与之相比G1和Parallel会有很多超过200ms的GC停顿。

                              三、补充

                              1.Stop-The-World

                              JVM在后台自动发起和自动完成的,在用户不可见的情况下,把用户正常的工作线程全部停掉,即GC停顿,这会带给用户不良的体验。从JDK1.3到现在,从Serial收集器-》Parallel收集器-》CMS-》G1,用户线程停顿时间不断缩短,但仍然无法完全消除。

                              2.为什么只有ParNew能与CMS收集器配合?

                              CMS是HotSpot在JDK1.5推出的第一款真正意义上的并发(Concurrent)收集器,第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。CMS作为老年代收集器,但却无法与JDK1.4已经存在的新生代收集器Parallel Scavenge配合工作,因为Parallel Scavenge(以及G1)都没有使用传统的GC收集器代码框架,而另外独立实现;而其余几种收集器则共用了部分的框架代码。所以如果老年代使用了CMS,那新生代只能使用ParNew。

                              3.CMS垃圾回收中,既然Mark Sweep会造成内存碎片,那么为什么不把算法换成Mark Compact呢?

                              答案其实很简答,因为当并发清除的时候,用Compact整理内存的话,原来的用户线程使用的内存还怎么用呢?要保证用户线程能继续执行,前提的它运行的资源不受影响嘛。Mark Compact更适合“Stop the World”这种场景下使用。

                              参考资料:

                                1. Serial收集器和ParNew收集器_wxy941011的博客-CSDN博客_serial parnew
                                2. 一文了解JVM全部垃圾回收器,从Serial到ZGC - 大天狗子 - 博客园
                                3. CMS垃圾收集器_mc90716_163的博客-CSDN博客
                                4. 五、Parallel Scavenge + Parallel Old 收集器 - 萧亦全 - 博客园
                                相关文章
                                |
                                3天前
                                |
                                算法 Java 程序员
                                深入理解Java的垃圾回收机制
                                【9月更文挑战第31天】在Java的世界里,有一个默默守护者,它负责清理不再使用的对象,确保内存的有效利用。这就是垃圾回收器(Garbage Collector, GC)。本文将带你一探究竟,了解它是如何工作的,以及为何我们需要关心它的存在。
                                |
                                5天前
                                |
                                监控 Java 程序员
                                深入理解Java中的垃圾回收机制
                                【9月更文挑战第29天】在Java编程的海洋中,垃圾回收(Garbage Collection, GC)是维持内存健康的灯塔。本文将带你探索GC的奥秘,从它的本质、工作机制到优化策略,让你的代码像海豚一样优雅地畅游。
                                |
                                6天前
                                |
                                存储 算法 Java
                                深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
                                本文介绍了 JVM 的内存区域划分、类加载过程及垃圾回收机制。内存区域包括程序计数器、堆、栈和元数据区,每个区域存储不同类型的数据。类加载过程涉及加载、验证、准备、解析和初始化五个步骤。垃圾回收机制主要在堆内存进行,通过可达性分析识别垃圾对象,并采用标记-清除、复制和标记-整理等算法进行回收。此外,还介绍了 CMS 和 G1 等垃圾回收器的特点。
                                18 0
                                深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
                                |
                                9天前
                                |
                                监控 算法 Java
                                深入解析Java中的垃圾回收机制
                                本文旨在全面解析Java的垃圾回收机制,探讨其工作原理、常见算法以及在实际开发中的应用。通过对这一重要主题的深入分析,希望帮助读者更好地理解Java虚拟机(JVM)如何管理内存,从而编写出更高效、稳定的Java应用程序。
                                |
                                14天前
                                |
                                监控 算法 Java
                                Java中的内存管理与垃圾回收机制
                                本文将深入探讨Java编程语言中的内存管理方式,特别是垃圾回收(Garbage Collection, GC)机制。我们将了解Java虚拟机(JVM)如何自动管理内存,包括对象创建、内存分配以及不使用对象的回收过程。同时,我们还将讨论不同的垃圾回收算法及其在不同场景下的应用。
                                |
                                13天前
                                |
                                监控 算法 Java
                                深入理解Java中的垃圾回收机制在Java编程中,垃圾回收(Garbage Collection, GC)是一个核心概念,它自动管理内存,帮助开发者避免内存泄漏和溢出问题。本文将探讨Java中的垃圾回收机制,包括其基本原理、不同类型的垃圾收集器以及如何调优垃圾回收性能。通过深入浅出的方式,让读者对Java的垃圾回收有一个全面的认识。
                                本文详细介绍了Java中的垃圾回收机制,从基本原理到不同类型垃圾收集器的工作原理,再到实际调优策略。通过通俗易懂的语言和条理清晰的解释,帮助读者更好地理解和应用Java的垃圾回收技术,从而编写出更高效、稳定的Java应用程序。
                                |
                                20天前
                                |
                                监控 算法 Java
                                Java中的内存管理:理解垃圾回收机制的深度剖析
                                在Java编程语言中,内存管理是一个核心概念。本文将深入探讨Java的垃圾回收(GC)机制,解析其工作原理、重要性以及优化方法。通过本文,您不仅会了解到基础的GC知识,还将掌握如何在实际开发中高效利用这一机制。
                                |
                                18天前
                                |
                                监控 算法 Java
                                深入理解Java中的垃圾回收机制(GC)
                                本文将探讨Java的自动内存管理核心——垃圾回收机制。通过详细解析标记-清除算法、复制算法和标记-整理算法等常用垃圾回收算法,以及CMS、G1等常见垃圾回收器,帮助读者更好地理解Java应用的性能优化和内存管理。同时,探讨分代收集、分区收集等策略在实际项目中的应用。结语部分总结了垃圾回收机制在Java开发中的重要性,并展望了未来可能的发展。
                                19 0
                                |
                                算法 Java
                                【Java 虚拟机原理】垃圾回收算法( Java VisualVM 工具 | 安装 Visual GC 插件 | 使用 Java VisualVM 分析 GC 内存 )
                                【Java 虚拟机原理】垃圾回收算法( Java VisualVM 工具 | 安装 Visual GC 插件 | 使用 Java VisualVM 分析 GC 内存 )
                                304 0
                                【Java 虚拟机原理】垃圾回收算法( Java VisualVM 工具 | 安装 Visual GC 插件 | 使用 Java VisualVM 分析 GC 内存 )
                                |
                                监控 算法 Java
                                【Java 虚拟机原理】垃圾回收算法 ( 设置 JVM 命令参数输出 GC 日志 | GC 日志输出示例 | GC 日志分析 )
                                【Java 虚拟机原理】垃圾回收算法 ( 设置 JVM 命令参数输出 GC 日志 | GC 日志输出示例 | GC 日志分析 )
                                210 0
                                【Java 虚拟机原理】垃圾回收算法 ( 设置 JVM 命令参数输出 GC 日志 | GC 日志输出示例 | GC 日志分析 )
                                下一篇
                                无影云桌面