Java 垃圾收集器核心原理

[亡魂溺海] 提交于 2020-04-16 08:02:09

【推荐阅读】微服务还能火多久?>>>

垃圾回收(Garbage Collection,GC),顾名思义就是释放垃圾占用的空间,防止内存泄露。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。

四大垃圾回收算法思想

  • 引用记数
    引用计数算法(Reachability Counting)是通过在对象头中分配一个空间来保存该对象被引用的次数(Reference Count)。如果该对象被其它对象引用,则它的引用计数加1,如果删除对该对象的引用,那么它的引用计数就减1,当该对象的引用计数为0时,那么该对象就会被回收。

  • 标记清除
    标记-清除算法(Mark-Sweep)是最基础的一种垃圾回收算法,它分为 2 部分,先把内存区域中的这些对象进行标记,哪些属于可回收标记出来,然后把这些垃圾拎出来清理掉。
    在这里插入图片描述

  • 复制算法
    复制算法(Copying)是在标记清除算法上演化而来,解决标记清除算法的内存碎片问题。
    在这里插入图片描述

  • 标记整理
    标记-整理算法(Mark-Compact)的标记过程仍然与标记清除算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,再清理掉端边界以外的内存区域。
    在这里插入图片描述

四种主要垃圾收集器

在这里插入图片描述

  • 串行垃圾回收器(Serial)
    它为单线程环境设计且只使用一个线程进行垃圾回收,会暂停所有用户线程,所以不适合服务器环境。

  • 并行垃圾回收器(Parallel)
    多个垃圾收集线程并行工作,此时用户线程是暂停的,适用于科学计算/大数据处理等弱交互场景。

  • 并发垃圾回收器(CMS)
    用户线程和垃圾收集线程同时执行(不一定并行,可能交替执行),不需要停顿用户线程,互联网公司多用它,适用对响应时间有要求的场景。

  • G1
    是一种服务端的垃圾收集器,应用在多处理器和大容量内容环境中,在实现高吞吐量的同时,尽可能的满足垃圾收集暂停时间的要求。具有以下特性:

    1. 像CMS收集器一样,能与应用程序线程并发执行
    2. 整理空间空间更快
    3. 需要更多时间来预测GC停顿时间
    4. 不希望牺牲大量的吞吐性能
    5. 不需要更大的Java Heap

七种垃圾回收

在这里插入图片描述

新生代

  • 串行GC(Serial、Serial Copying)
    一个单线程的收集器,在进行垃圾收集时候,必须暂停其它所有的工作线程直到它收集结束。
    在这里插入图片描述
    串行收集器是最古老的、最稳定以及效率最高的收集器,只使用一个线程去回收但其在进行垃圾收集过程中可能会产生较长的停顿(STW “Stop-The-Word”状态)。虽然在收集垃圾过程中需要暂停所有其他的工作线程,但是它简单高效,对于限定单个CPU环境来说,没有线程交互的开销可以获得最高的单线程垃圾收集效率,因此Serial垃圾收集器依然是java虚拟机运行在Client模式下默认的新生代垃圾收集器。


    对应JVM参数: -XX:+UseSerialGC
    开启后会使用:Serial(Young区用)+Serial Old(Old区用)的收集器组合。
    表示:新生代、老年代都会使用串行回收收集器,新生代使用复制算法,老年代使用标记-整理算法

  • 并行GC(ParNew)
    使用多线程进行垃圾回收,在垃圾收集时,会Stop-the-world暂停所有的工作线程直到它收集结束。
    在这里插入图片描述
    ParNew收集器其实就是Serial收集器新生代的并行多线程版本,最常见的应用场景是配合老年代的CMS GC工作,其余的行为和Serial收集器完全一样,ParNew垃圾收集器在垃圾收集过程中同样也要暂停其它的工作线程。它是很多java虚拟机运行在Server模式下新生代的默认垃圾收集器。


    常用对应JVM参数:-XX:+UseParNewGC 启用ParNew收集器,只影响新生代的收集,不影响老年代。开启上述参数后会使用:ParNew(Young区用)+Serial Old的收集器组合,新生代使用复制算法,老年代采用标记-整理算法。

  • 并行回收GC(Parallel、Parallel Scavenge)
    就是串行收集器在新生代和老年代的并行化
    在这里插入图片描述
    Parallel Scavenge收集器类似ParNew也是一个新生代收集器,使用复制算法,也是一个并行的多线程的垃圾收集器,俗称吞吐量优先收集器。


    它重点关注的是:
    可控制的吞吐量 (Thoughput=运行用户代码时间/(运行用户代码时间+垃圾收集时间),也即比如程序运行100分钟,垃圾收集时间1分钟,吞吐量就是99%)。高吞吐量意味着高效利用CPU时间,它多用于在后台运算而不需要太多交互的任务。
    自适应调节策略也是ParallelScavenge收集器与ParNew收集器一个重要区别。自适应调节策略:虚拟机会根据当前系统的运行情况收集性能监控信息,动态调控这些参数以提供最合适的停顿时间-XX:MaxGCPauseMills或最大的吞吐量。

老年代

  • 并行GC(Serial Old、Serial MSC)
    Serial Old是Serial垃圾收集器老年代版本,它同样是个单线程的收集器,使用标记-整理算法,这个收集器也主要运行在Client默认的java虚拟机默认的老年代的垃圾收集器。

  • 串行GC(Parallel Old、Parallel MSC)
    Parallel Old收集器是Parallel Scavenge的老年代版本,使用多线程的标记-整理算法,Parallel Old收集器在JDK1.6才开始提供。
    在JDK1.6之前,新生代使用ParallelScavenge收集器只能搭配老年代的Serial Old收集器,只能保证新生代的吞吐量优先,无法保证整体的吞吐量。在JDK1.6之前(Parallel Scavenge + Serial Old)。
    Parallel Old正是为了在老年代同样提供吞吐量优先的垃圾收集器,如果系统对吞吐量要求比较高,JDK1.8后可以优先考虑新生代Parallel Scavenge和老年代Parallel Old收集器搭配策略。在JDK1.8及以后(Parallel Scavenge + Parallel Old)


    JVM常用参数:-XX:UserParallelOldGC使用Parallel Old收集器,设置该参数后,新生代Parallel + 老年代Parallel Old

  • CMS收集器(Concurrent Mark Sweep:并发标记清除)
    是一种以获取最短停顿时间为目标的收集器。适合应用在互联网站或B/S系统的服务上,这类应用尤其重视服务器的响应速度,希望系统停顿时间最短。CMS非常适合推内存大、CPU核数多的服务器端应用,也是G1出现之前大型应用的首选收集器。
    在这里插入图片描述
    CMS并发标记清除,并发收集低停顿,并发指的是与用户线程一起执行。


    开启该收集器的JVM参数:-XX:+UseConcMarkSweepGC 开启开启该参数后自动将-XX:+UseParNewGC打开。
    开启该参数后,使用ParNew(Young区用)+CMS(Old区用)+Serial Old有收集器组合,Serial Old将作为CMS出错的后备收集器。

    四步过程:

    1. 初始标记(CMS initial mark):只有标记一起GC Roots能直接关联的对象,速度很快,仍然需要暂停所有的工作线程。
    2. 并发标记(CMS concurrent mark)和用户线程一起:进行GC Roots跟踪过程,和用户线程一起工作,不需要暂停工作线程。主要标记过程,标记全部对象。
    3. 重新标记(CMS remark):为了修正在并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,仍然需要暂停所有的工作线程。
    4. 并发清除(CMS concurrent sweep)和用户线程一起:清除GC Roots不可达对象,和用户线程一起工作,不需要暂停工作线程。基于标记结果,直接清理对象。

    所以总体上来看CMS收集器的内存回收和用户线程是一起并发地执行。
    在这里插入图片描述
    优点:并发收集低停顿
    缺点:并发执行对CPU资源压力。采用的标记清除算法会导致大量碎片。
    核心思想是将整个推内个区域划分成大小相同的子区域(Region),在JVM启动时会自己设置这些区域的大小,在推的使用上,G1并不要求对象的存储一定是物理连续的只要逻辑上连续即可,每个分区也不会固定地为某个代服务,可按需在年轻代和老年代之间切换。启动时可以通过参数:-XX:G1HeapRegionSize=n可指定分区大小(1MB~32MB且必须是2的幂),默认将整个推划分为2048个分区。
    大小范围在1MB~32MB,最多能设置2048个区域,也即能支持的最大内存为:32MB*2048=64G




G1
区域化内存碎片Region,整体为了一些不连续的内存区域,避免了全内存的GC操作。

参数 新生代垃圾收集器 新生代算法 老年代垃圾收集器 老年代算法
-XX:+UseSerialGC SerialGC 复制 SerialOldGC 标整
-XX:+UseParNewGC ParNew 复制 SerialOldGC 标整
-XX:+UseParallelGC、-XX+UseParallelOldGC Parallel[Scavenge] 复制 Parallel Old 标整
-XX:+UseConcMarkSweepGC ParNew 复制 CMS + Serial Old的收集器组合(Serial Old作为CMS出错的后备收集器) 标整
-XX:+UseGqGC G1整体上采用标记-整理算法 局部通过复制算法,不会产生内存碎片 $1600
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!