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 收集器 - 萧亦全 - 博客园
                                相关文章
                                |
                                4天前
                                |
                                JavaScript 前端开发 算法
                                Java Script 中的垃圾回收机制有哪些缺点
                                Java Script 中的垃圾回收机制有哪些缺点
                                19 0
                                |
                                4天前
                                |
                                算法 Java 关系型数据库
                                掌握这3个技巧,你也可以秒懂JAVA性能调优和jvm垃圾回收
                                JVM 是一个虚拟化的操作系统,类似于 Linux 和 Window,只是他被架构在了操作系统上进行接收 class 文件并把 class 翻译成系统识别的机器码进行执行,即 JVM 为我们屏蔽了不同操作系统在底层硬件和操作指令的不同。
                                27 0
                                |
                                4天前
                                |
                                存储 Java 数据安全/隐私保护
                                【JVM】Java虚拟机栈(Java Virtual Machine Stacks)
                                【JVM】Java虚拟机栈(Java Virtual Machine Stacks)
                                39 0
                                |
                                4天前
                                |
                                监控 算法 Java
                                深入理解Java中的垃圾回收机制
                                【2月更文挑战第13天】 本文旨在深入剖析Java中的核心机制之一——垃圾回收(Garbage Collection, GC)。与传统的摘要不同,我们不会概述全文内容,而是直接点明文章将探讨的重点问题:如何合理利用垃圾回收机制优化Java应用性能。通过分析不同垃圾回收器的工作原理与特点,本文将指导开发者识别和处理内存泄漏,选择合适的垃圾回收策略,以及评估垃圾回收行为对应用性能的实际影响。
                                |
                                4天前
                                |
                                存储 Java
                                深入理解Java虚拟机:JVM内存模型
                                【4月更文挑战第30天】本文将详细解析Java虚拟机(JVM)的内存模型,包括堆、栈、方法区等部分,并探讨它们在Java程序运行过程中的作用。通过对JVM内存模型的深入理解,可以帮助我们更好地编写高效的Java代码,避免内存溢出等问题。
                                |
                                4天前
                                |
                                算法 Java Go
                                Go vs Java:内存管理与垃圾回收机制对比
                                对比了Go和Java的内存管理与垃圾回收机制。Java依赖JVM自动管理内存,使用堆栈内存并采用多种垃圾回收算法,如标记-清除和分代收集。Go则提供更多的手动控制,内存分配与释放由分配器和垃圾回收器协同完成,使用三色标记算法并发回收。示例展示了Java中对象自动创建和销毁,而Go中开发者需注意内存泄漏。选择语言应根据项目需求和技术栈来决定。
                                |
                                4天前
                                |
                                缓存 算法 安全
                                【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍(二)
                                【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍
                                23 0
                                |
                                4天前
                                |
                                缓存 Java C#
                                【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍(一)
                                【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍
                                92 0
                                |
                                3天前
                                |
                                存储 算法 Java
                                Java一分钟之-Java内存模型与垃圾回收机制概览
                                【5月更文挑战第16天】本文简述Java内存模型(JMM)和垃圾回收(GC)机制。JMM包括栈、堆、方法区、程序计数器和本地方法栈。GC负责回收不再使用的对象内存,常用算法有新生代、老年代和全堆GC。文章讨论了内存溢出、死锁和GC性能等问题,提出了解决方案,如调整JVM参数和优化GC策略。此外,还强调了避免内存泄漏、大对象管理及正确释放资源的重要性。理解这些概念有助于提升Java应用的性能和稳定性。
                                13 1
                                |
                                4天前
                                |
                                存储 算法 Java
                                了解Java内存管理与垃圾回收机制
                                了解Java内存管理与垃圾回收机制
                                8 0

                                热门文章

                                最新文章