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

垃圾回收器_经典垃圾回收器

本文由编程笔记#小编为大家整理,主要介绍了经典垃圾回收器相关的知识,希望对你有一定的参考价值。常见的垃圾回收器种类:
本文由编程笔记#小编为大家整理,主要介绍了经典垃圾回收器相关的知识,希望对你有一定的参考价值。


常见的垃圾回收器种类:



  • 新生代垃圾回收器



    1. Serial


    2. ParNew


    3. Parallel Scavenge



  • 老年代垃圾回收器



    1. Serial Old


    2. Parallel Old


    3. CMS



  • 新生代和老年代垃圾回收器



    1. G1




上图展示了七种作用于不同分代的收集器, 如果两个收集器之间存在连线, 就说明它们可以搭配使用。



前置名称规范:



  1. 并发:并行描述的是多条垃圾收集器线程之间的关系。


  2. 并行:并发描述的是垃圾收集器线程与用户线程之间的关系。





Serial收集器

 Serial收集器运行示意图,如下:

经典垃圾回收器

如上所示,当用户线程都执行到了安全点时,暂停用户线程,并且会唤醒GC线程进行垃圾回收,收集完成后,停止GC 线程,开启用户线程。


Serial 收集器是一款适用于新生代单线程垃圾回收器,采用了标记-复制算法





这里的单线程的含义:


    1. 并不是意味这当前GC 线程的工作线程只有一个,而是强调当GC 线程工作的时候,用户线程必须停止,也就是我们常说的STW(stop the world)




适用场景:



  1. Client模式


  2. 系统资源少的的场景



优点:



  1. 简单高效


  2. 占用资源


  3. 单核处理器回收效率高


缺点:



  1. 需要stop the world,且时间相对较长。


可以用 -XX:+UserSerialGC 来选择 Serial 作为新生代收集器


ParNew收集器

ParNew收集器的运行示意图如下:

经典垃圾回收器

ParNew收集器可以理解是Serial收集器的多线程版本,其实和Serial并没有很多的区别,如上所示,ParNew收集器运行示意图中,当用户线程到达安全点的时候,会暂停所有的用户线程,并且启动GC 线程,默认情况下,GC 线程数和CPU数量一致。 






1. 可以使用-XX:ParallelGCThreads参数来限制垃圾收集的线程数。


2. 由于上下文切换开销,ParNew收集器在单核心处理器的环境中绝对不会有比Serial收集器更好的效果。




ParNew是一款新生代多线程垃圾回收器,采用了标记-复制算法


使用场景:



  1. 服务端应用


  2. 与CMS垃圾回收器搭配使用




Parallel Scavenge收集器

Parallel Scavenge收集器的运行示意图如下:

经典垃圾回收器

Parallel Scavenge收集器在运行效果上类似于ParNew收集器。


Parallel Scavenge是一款新生代的垃圾回收器,同样也是采用了标记-复制算法。


那么和ParNew 收集器的区别是什么呢? 


Parallel Scavenge收集器的特点是它的关注点与其他收集器不同,如:



  • CMS等收集器关注用户线程的停顿时间


  • Parallel Scavenge收集器关注可控制的吞吐



所谓吞吐量,即:



  • 吞吐量 = 运行用户代代码时间/(运行用户代码时间+垃圾收集时间)


比如:虚拟完成某个任务花费了100分钟(用户代码时间+垃圾收集时间),其中垃圾收集花费了1分钟,那么吞吐量为99%。


与考虑用户线程停顿时间的收集器的区别是什么呢?



  • CMS等垃圾回收器:停顿时间越短就越适合需要与用户交互或需要保证服务响应质量的程序,良好的响应速度能提升用户体验


  • Parallel Scavenge收集器:高吞吐量则可以最高效率地利用处理器资源, 尽快完成程序的运算任务。



所以说,Parallel Scavenge收集器适合的场景为:



  1. 注重吞吐量


  2. 高效利用CPU


  3. 高效运算且无需交互



那么如何控制吞吐量呢?


可以使用参数来精确控制吞吐量:



  1. -XX:MaxGCPauseMillis:控制最大垃圾收集停顿时间, 一个大于0的毫秒数


  2. -XX:GCTimeRatio:直接设置吞吐量大小, 一个大于0小于100的整数



备注:



  1. JDK8的默认新生代垃圾回收器:

    经典垃圾回收器



Serial Old收集器


Serial Old垃圾收集器的运行示意图如下:

经典垃圾回收器

Serial Old是Serial收集器的老年代版本, 它同样是一个单线程收集器, 使用标记-整理算法。

使用场景:



  1. 客户端模式下,HotSpot虚拟机使用


  2. 服务端模式下, 有两种用途:



    1. 与Parallel Scavenge收集器搭配使用


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



 

Parallel Old收集器

Parallel Old的运行示意图如下:

经典垃圾回收器

Parallel Old是Parallel Scavenge收集器的老年代版本, 支持多线程并发收集, 基于标记-整理算法。


Parallel Old收集器出现后, “吞吐量优先”收集器终于有了比较名副其实的搭配组合(在此之前只能搭配Serial old 使用), 在注重吞吐量或者处理器资源较为稀缺的场合, 都可以优先考虑Parallel Scavenge加Parallel Old收集器这个组合。


CMS收集器

下图是CMS垃圾回收器的运行示意图:

经典垃圾回收器

CMS(Concurrent Mark Sweep) 收集器是一种以获取最短回收停顿时间为目标的收集器。


CMS收集器是基于标记-清除算法实现,主要的流程分为:



  1. 初始标记:标记出GC root 直接关联的对象,速度很快,需要Stop the world。


  2. 并发标记:根据第一步标记出的直接关联对象进行搜素标记其他对象,这个阶段耗时较长,但是可以与用户线程并发执行。


  3. 重新标记:修正并发标记过程中,由于用户线程修改导致的的一部分对象(采用增量更新的方式)。


  4. 并发清除:清理删除掉标记阶段判断的已经死亡的对象,由于是采用标记-清除算法,所以不需要移动对象,即可以与用户线程并发执行。



从上面的步奏来看,最耗时的阶段是并发标记和并发清除,但是可以与用户线程并发执行,所以说达到低停顿的目的。


那么是不是就没缺点了呢?


CMS至少有三个缺点:



  1. 对处理器资源非常敏感,并发阶段抢占用户线程资源,导致总吞吐量下降, 默认启动的回收线程数是总线程数的3/4。


  2. 无法处理“浮动垃圾”可能导致 Concurrent Mode Failure异常,进而Full gc



    1. 浮动垃圾产生:由于并发阶段(并发标记和并发清除),用户线程还在执行,即垃圾还在产生。


    2. Concurrent Mode Failure异常原因:并发阶段垃圾,用户线程还在执行,需要为其预留空间,浮动垃圾产生可能填满用户运行空间,导致执行失败,进而使用Serial Old进行垃圾收集,进入Full gc。



  3. 空间碎片化, 基于“标记-清除”算法固有问题,导致给大对象分配内存较难,进而进入Full GC



    1. 解决办法:  CMS收集器在执行过若干次不整理空间的Full GC之后, 下一次进入Full GC前会先进行碎片整理。使用参数:-XX:CMSFullGCsBeforeCompaction 设置




其他缺点:



  1. 需要全量扫描对象:CMS虽然是老年代的gc,但仍要扫描新生代来确认老年代存活的对象。


经典垃圾回收器


重点:全量扫描年轻代和老年代岂不是很慢?那我们如何解决呢?


解决办法:



  • 新生代:Minor GC,新生代垃圾回收之后,存活的对象很少,如果在扫描新生代之前进行一次minor GC,那么整个情况就会好很多。


  • 老年代:卡表,新生代指向了老年代那些地方存在跨带引用,我们只需要扫描卡表即可得出老年代引用新生代。




Garbage First(G1)

G1垃圾回收器的运行示意图如下:

经典垃圾回收器

如上所示, G1收集器的运作过程大致可划分为以下四个步骤:



  1. 初始标记



    1. 标记一下GC Roots能直接关联到的对象。


    2. 修改指针(指针的意义,下面描述)的值, 让下一阶段用户线程并发运行时, 能正确地在可用的Region中分配新对象。



  2. 并发标记



    1. 从GC Root开始对堆中对象进行可达性分析, 可与用户程序并发执行。


    2. 处理SATB记录下的在并发时有引用变动的对象



  3. 最终标记



    1. 处理并发阶段结束后仍遗留下来的最后那少量的SATB记录。



  4. 筛选回收



    1. 更新Region的统计数据, 对各个Region的回收价值和成本进行排序。


    2. 制定回收计划。


    3. 决定回收的那一部分Region的存活对象复制到空的Region。


    4. 理掉整个旧Region的全部空间。




上述过程直接中,只有并发标记可以通用户线程一起执行,其他的都需要停止用户线程。所以说G1的目的并不是一味的追求低延迟,而是在保证延迟可控的情况下,能带来最大的吞吐量。


G1的意义

Garbage First(简称G1) 收集器开创了收集面向局部收集的设计思路和基于Region的内存布局形式。


那什么是面向局部收集呢?

其他收集器, 包括CMS在内, 垃圾收集的目标范围要么是整个新生代(Minor GC) , 要么就是整个老年代(Major GC) , 再要么就是整个Java堆(Full GC)。 而G1跳出了这个樊笼, 它可以面向堆内存任何部分来组成回收集 (Collection Set, 一般简称CSet) 进行回收,衡量标准变为了 不再是它属于哪个分代, 而是哪块内存中存放的垃圾数量最多, 回收收益最大。


其中基于Region的内存布局是实现面向局部收集的关键。


那什么是基于Region的内存布局呢?




  1. G1不再坚持固定大小以及固定数量的分代区域划分, 而是把连续的Java堆划分为多个大小相等的独立区域(Region)。



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



  2. 每一个Region都可以根据需要, 扮演新生代的Eden空间、 Survivor空间, 或者老年代空间, 对扮演不同角色的Region采用不同的策略去处理。


  3. Region中还有一类特殊的Humongous区域, 专门用来存储大对象



    1. G1认为只要大小超过了一个Region容量一半的对象即可判定为大对象。




所以最终G1面向局部收集的Region内存布局如下图所示:



那么这样设计的目的是什么呢?

设计者希望建立一款能够建立起“停顿时间模型”(PausePrediction Model) 的收集器, 停顿时间模型的意思是能够支持指定在一个长度为M毫秒的时间片段内, 消耗在垃圾收集上的时间大概率不超过N毫秒这样的目标。


为什么这样的内存设计可以建立停顿时间模型呢?

主要有以下原因:



  1. 将Region作为单次回收的最小单元 即每次收集到的内存空间都是Region大小的整数倍, 这样可以有计划地避免在整个Java堆中进行全区域的垃圾收集。


  2. G1收集器去跟踪各个Region里面的垃圾堆积的“价值”大小, 价值即回收所获得的空间大小以及回收所需时间的经验值, 然后在后台维护一个优先级列表, 每次根据用户设定允许的收集停顿时间(使用参数-XX:MaxGCPauseMillis指定, 默认值是200毫秒) , 优先处理回收价值收益最大的那些Region。



G1需要解决的问题主要有:

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

解决思路:使用记忆集避免全堆作为GC Roots扫描,每个Region都维护有自己的记忆集, 这些记忆集会记录下别的Region指向自己的指针。


结果:

由于Region数量比传统收集器的分代数量明显要多得多, 因此G1收集器要比其他的传统垃圾收集器有着更高的内存占用负担。


并发标记阶段如何保证收集线程与用户线程互不干扰地运行?


主要问题及解决办法:



  1. 并发标记,导致的引用关系被破坏。CMS收集器采用增量更新算法实现, 而G1收集器则是通过原始快照(SATB) 算法来实现的。


  2. 回收过程中新创建对象的内存分配 G1为每一个Region设计了两个指针, 把Region中的一部分空间划分出来用于并发回收过程中的新对象分配。 如果内存回收的速度赶不上内存分配的速度,G1收集器也要被迫冻结用户线程执行, 导致Full GC而产生长时间“Stop The World”。



怎样建立起可靠的停顿预测模型?





用户通过-XX:MaxGCPauseMillis参数指定的停顿时间


只意味着垃圾收集发生之前的期望值, 但G1收集器要怎么做才能满足用户的期望呢?




G1收集器会记录每个Region的回收耗时、 每个Region记忆集里的脏卡数量等各个可测量的步骤花费的成本,然后维护一个优先级列表,根据停顿时间来决定回收的区域。







注意;


不能将停顿时间设置太小,否则可能导致平凡的Full gc。通常情况下100-200ms是比较合适的。





G1的GC 模式



  1. Young GC:回收eden区域以及Survivor区域,并将活的对象复制到Old区域和其他的Survivor区域。


  2. Mix GC:回收整个Young 区域+一部分Old区域



G1没有Full GC 的概念,需要Full gc 则调用Serial Old进行全堆扫描。


适用场景:要求尽可能可控 GC 停顿时间;内存占用较大的应用。可以用 -XX:+UseG1GC 使用 G1 收集器,jdk9 默认使用 G1 收集器。





其他:


为什么新生代不使用:标记-整理算法:


https://blog.csdn.net/weixin_41539756/article/details/95797617





—  —

原创内容,未经账号授权,禁止随意转载。

点这里

推荐阅读
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
  • 阿里Treebased Deep Match(TDM) 学习笔记及技术发展回顾
    本文介绍了阿里Treebased Deep Match(TDM)的学习笔记,同时回顾了工业界技术发展的几代演进。从基于统计的启发式规则方法到基于内积模型的向量检索方法,再到引入复杂深度学习模型的下一代匹配技术。文章详细解释了基于统计的启发式规则方法和基于内积模型的向量检索方法的原理和应用,并介绍了TDM的背景和优势。最后,文章提到了向量距离和基于向量聚类的索引结构对于加速匹配效率的作用。本文对于理解TDM的学习过程和了解匹配技术的发展具有重要意义。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 关于CMS收集器的知识介绍和优缺点分析
    本文介绍了CMS收集器的概念、运行过程和优缺点,并解释了垃圾回收器的作用和实践。CMS收集器是一种基于标记-清除算法的垃圾回收器,适用于互联网站和B/S系统等对响应速度和停顿时间有较高要求的应用。同时,还提供了其他垃圾回收器的参考资料。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • 生成对抗式网络GAN及其衍生CGAN、DCGAN、WGAN、LSGAN、BEGAN介绍
    一、GAN原理介绍学习GAN的第一篇论文当然由是IanGoodfellow于2014年发表的GenerativeAdversarialNetworks(论文下载链接arxiv:[h ... [详细]
  • 基于事件驱动的并发编程及其消息通信机制的同步与异步、阻塞与非阻塞、IO模型的分类
    本文介绍了基于事件驱动的并发编程中的消息通信机制,包括同步和异步的概念及其区别,阻塞和非阻塞的状态,以及IO模型的分类。同步阻塞IO、同步非阻塞IO、异步阻塞IO和异步非阻塞IO等不同的IO模型被详细解释。这些概念和模型对于理解并发编程中的消息通信和IO操作具有重要意义。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
author-avatar
_Rongrise
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有