垃圾收集器简单说明(《 深入理解 java 虚拟机》读后摘录)

本贴最后更新于 3034 天前,其中的信息可能已经物是人非
该文简述了常用垃圾收集器的特点与区别,内容主要来自《深入理解java虚拟机》,方便在对比的时候有个参考!
 
这是收集器的关系图:
 
 
 
 
这是hotspot 的七种作用于不同分器之间有连线,说明他代的收集器,,如果两个收集们可以搭配使用,虚拟机所处的区域,表示新生代还是老年带收集器。

新生代的垃圾收集器有:Serial收集器、ParNew收集器、Parallel Scavenge收集器

老年代的垃圾收集器有:Serial Old收集器、Parallel Old收集器、CMS收集器、G1收集器

概念解释:
并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态
并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户程序继续运行,而垃圾收集程序运行在另一个cou核心上
Stop-The-World  : 简称STW ,表示全局暂停,表现为JAVA代码停止,native代码可以执行,但是不能和JVM交互,大部分情况是GC引起的
 
垃圾收集算法说明:标记-清除算法、复制算法、标记-整理算法、分代收集算法
 
标记-清除算法
该算法如同它的名字一样,分为两个阶段:标记、清除。首先标记出所有需要回收的对象,然后,统一清除这些被标记的对象。该算法的缺点是:1、效率不高;2、产生大量不连续的内存碎片,导致有大量内存剩余的情况下,由于,没有连续的空间来存放较大的对象,从而触发了另一次垃圾收集动作。

复制算法

由于标记-清除算法的效率不高,从而提出了复制算法。复制算法将可用的内存分成两样大小的两块,每次只使用其中一块内存。当这块内存用完之后,就把还存活的对象复制到另外一块上面,然后,把这块清空。复制算法克服了标记-清除算法的两个缺点,但是太浪费内存,相当于内存空间减小了一半。

随着时间的积累,现在使用的复制算法的虚拟机,不再是把内存分为1:1的两块。因为98%的对象是寿命很短的,创建之后,很快就被回收了,存活下来的只有2%,所以,用来存储存活对象的内存区,可以小一些。现在的商业虚拟机是把可用内存分为一个较大的Eden空间和两个较小的Survivor空间,每次使用Eden和其中的一块Survivor。当回收时,把Eden和Survivor中的存活对象一次复制到另一块Survivor内存区上,然后把Eden和刚才用过的Survivor空间清空。HotSpot虚拟机默认Eden和Survivor的大小比例是8:1,这样,每次新产生的对象可以使用90%的内存空间。

标记-整理算法

从名字可以看出,该算法是对“标记-清除”算法的改进升级版。同样的该算法分为两个阶段:标记、整理。标记阶段同“标记-清除”算法。整理阶段,不是直接对标记对象进行清理,而是让所有存活的对象都移动到一端,然后,直接把边界以外的内存清空。这就解决了“标记-清除”算法会造成大量不连续内存碎片的问题。

分代收集算法

分代收集算法是根据对象的存活周期的不同,将内存划分为几块。当前的商业虚拟机的垃圾收集都采用了该算法。一般把Java堆分成新生代(年轻代)和老年代(年老代)。这样就可以根据各年代中对象的存活周期来选择最合适的收集算法了。新生代,由于只有少量的对象能存活下来,所以选用“复制算法”,只需要付出少量存活对象的复制成本。老年代,由于对象的存活率高,没有额外的空间分担,就必须使用“标记-清除”或“标记-整理”算法。

1.Serial 收集器【单线程-复制算法-新生代
 
Serial 收集器是最基本,历史最久的收集器(单线程),在jdk1.3.1之前是虚拟机新生代收集的唯一选择,在进行垃圾收集工作的时候必须暂停所有其他的工作线程(用户不可见的情况下把用户的正常工作线程停掉一段时间),直到收集结束。
jvm Client 模型下的默认新生代收集器,对于单个cpu的环境来说,Serial  由于没有线程交互的开销,收集效率更好。
 
 
运行示意图:
 
2.ParNew 收集器【多线程-并行-复制算法-新生代
 
ParNew 其实就是Serial收集器的多线程版本,除了使用多个线程进行垃圾收集,其它行为(控制参数、收集算法、STOP THE WORD 、对象分配规则、回收策略)和Serial 完全一致.与Serial 共用了很多代码。
它是许多运行jvm server 模式中首选的新生代收集器,其中一个与性能无关且很重要的原因是,目前只有它能与CMS收集器配合工作(请看收集器关系图)
 
运行关系图(ParNew /Serial old):
 
默认开启的收集线程数与cpu核心数相同,内核较多的情况下可以使用参数   -XX: ParallelGcThreads 参数来限制收集线程数
-XX: +UseParNewGC  强制指定  ParNew收集器
-XX: +UseConcNarkSweep-GC 指定cms收集器,新生代收集器将默认为ParNew
 
3.Parallel Scavenge 收集器 【多线程-并行-复制算法-新生代】
 
Parallel Scavenge 收集器的特点是它 的关注点与其他收集器不同,CMS等关注点是尽可能的缩短垃圾回收时用户线程的停顿时间,而Parallel Scavenge 收集器的目标是达到一个可控制的吞吐量(Throughput)。所谓的吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即:吞吐量=运行用户代码时间 /  (运行用户代码时间+垃圾收集时间),虚拟机总共运行100分钟,其中垃圾收集花了1分钟,那么吞吐量就是99%。
 
停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验;而高吞吐量则适合高效利用CPU时间的应用,例如运算任务和交互较少的应用.
 
Parallel Scavenge 收集器提供  -XX: MaxGCPauseMillis 参数控制最大垃圾收集停顿时间(取值范围大于0)
                                                  -XX: GCTimeRatio 参数控制吞吐量大小,默认值为99(取值范围1-99)
                                                  -XX:+UseAdaptiveSizePolicy 自动调整新生代停顿/吞吐的开关(和ParNew的一个重要区别)
 
 -XX: MaxGCPauseMillis:该参数不是越小越好(收集速度更快),GC的停顿时间缩短是以牺牲吞吐量和新生代空间来换取的。
                                   例一:系统新生代调小一点,收集200M,当然要比收集500M速度要快
                                   例二:原来10秒收集一次,每次停顿100毫秒,现在5秒收集一次,每次停顿70毫秒,停顿降低了,但是吞吐量也降低了(按60秒算,60/10*100=600ms < 60/5*70=1400ms
 
  -XX: GCTimeRatio表示用户程序占用总时间的比值,垃圾收集是吞吐量的倒数;默认为:99,就是允许最大99%,垃圾收集即【1/(1+99)=0.01】,垃圾收集占1%,如设置为19,吞吐量是95%,垃圾收集占5%【1/(1+19)=0.05】)
 
 -XX:+UseAdaptiveSizePolicy:开启则不需要手动指定新生代大小-Xmn、eden与Survivor的比例-XX:Sur-vivorRatio、晋升老年的年龄-XX:Pretenure-SizeThreshold等参数,设置最大堆-Xmx和以上两个参数就好,系统会根据当前系统运行情况手机性能监控信息,动态调整这些参数提供合适的停顿时间和吞吐(GC自适应调节策略GC Er-Scavenge),比较适合对收集器运作原理不了解的朋友。
 
4.Serial Old 收集器 【单线程-标记整理算法-老年代】
 
该收集器是Serial 收集器的老年代版本主要在client 模式下的 JVM使用。
如果在 server 模式下有两大用途:
1.在jdk以及之前版本中与 Parallel Scavenge 收集器配合使用。
2.作为CMS 收集器的后备预案
 
运行图:
 
5.Parallel Old 收集器【多线程-标记整理算法-老年代】
 
Parallel Old 收集器 是Parallel 收集器 的老年代版本,使用多线程和“标记-整理算法”
该收集器在jdk1.6中开始提供,在此之前新生代收集器如果选择了Parallel Scavenge,则老年代收集器只能选择Serial Old 收集器。
由于老年代Serial Old收集器的性能“拖累”,使用Parallel Scacenge收集器未必能在“整体"应用上获得吞吐量最大化的效果,有时候还不如ParNew+CMS的组合的整体性能好
 
Parallel Old 收集器出现后,Parallel Scacenge(吞吐量优先)有了比较名副其实的组合。在注重吞吐量和对cpu资源比较敏感的场合都可以优先考虑Parallel Scacenge + Parallel Old
 
运行图:
 
 
6.CMS收集器 【多线程-标记清除算法-老年代】

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,使用“标记-清除”算法。

      CMS收集器分4个步骤进行垃圾收集工作: 1.初始标记(STW) 2.并发标记 3.重新标记(STW) 4.并发清除

    

      其中“初始标记”、“重新标记”是需要暂停其它所有工作线程的。初始标记只是标记一下GC Roots 能直接关联到的对象,速度很快,并发标记就是进行GC RootsTracing的过程,重新标记是修正并发标记后产生变动的一部分对象(通常比初始标记稍微长一点);通常情况下标记耗时:初始标记<重新标记<并发标记


      缺点:

      1.cms收集器对CPU资源非常敏感,并发阶段虽然不会导致用户线程停顿,但是会因为占用一部分线程导致程序变慢,总吞吐降低。(默认回收线程是(CPU数量*3)/4,也就是4核以上时垃圾回收占用不少于25%的CPU资源,内核低于25%影响更大,为了应付突然用户执行速度降低较大的情况,虚拟机提供了“I-cms”,垃圾回收线程和用户线程交替执,这样会让垃圾回收时间更长,但是会对用户影响较小,现在不推荐使用I-CMS了)

      2.CMS无法处理浮动垃圾(Floating Garbage),可能会导致"Concurrent Mode Fail-ure" 失败而导致另一次Full GC的产生。由于CMS并发清理用户线程在运行,会持续有新垃圾产生,这部分出现在标记过程后,CMS无法在当次收集清理掉,需要下一次GC时清理,就叫“浮动垃圾"。

        由于垃圾收集,用户线程在运行需要预留足够的内存,因此CMS收集器不像别的收集器要等到老年代几乎完全被填满了再收集,需要预留一部分内存提供并发收集时候的程序运行使用,JDK1.6默认CMS收集器默认启动阈值是92%,如果预留的空间不够用户线程使用,会出现"Concurrent Mode Faillure"失败,这时候虚拟机启动后备方案,临时启动Se-rial Old 收集器来重新收集老年代,这样收集时间比较长, 所有:参数-XX: CM SIniti-atingOccupancyFraction设置太高容易导致大量 "Concurrent Mode Failure"失败,导致性能下降.

       3.由于标记-清除算法实现的收集器会导致大量空间碎片,会给大对象内存分配带来麻烦,导致提前(总体空间够)出发FULL GC ,为了解决这个问题,

        CMS提供了-XX: +UseCMSCom-PactAtFullCollection开关参数(默认开),用来在CMS顶不住要Full GC的时候进行内存碎片整理,内存整理无法并发,空间碎片问题解决了,但是停顿时间会变长。

        CMS提供了-XX: CMSFullGCsBe-foreCompaction参数用来设置执行多少次不压缩的Full GC后进行一次带压缩的FULL GC,默认值为0,表示每次Full GC 都要进行碎片整理

 

运行图:
 
7.G1收集器 【多线程-标记整理算法-不分代】
 
  G1(Garbage First)收集器,基于“标记-整理”算法,可以非常精确地控制停顿。
特点:
        1.并行与并发:充分利用多CPU/多核硬件优势来缩短STW,部分其它收集器需要停顿JAVA线程进行GC,
        2.分代收集:G1依然保留分代,但是G1可以不需要其它收集器配合独立管理整个GC堆,能采用不同的方式处理新建对象、存活一段时间对象、多久GC后的对象以获取更好的手机效果。
        3.空间整合:G1从整体上看是基于“标记-整理”算法,从局部看(两个Region之间)上看是基于“复制”算法,这两种算法都不会产生内存碎片。
        4.可预测的停顿:这是G1相对CMS的另一个优势,降低停顿是G1和CMS共同的关注点,但是G1除了降低停顿,还能提供可预测的时间模型,能让使用者明确指定赢长度为M毫秒的时间片内,消耗在垃圾收集上的时间不超过N毫秒,这几乎是实时java(RTSJ)的垃圾收集器的特征咯。
 
    G1之前的收集器都是进行整个新生代/老年代的收集,G1将堆分为多个大小相等的独立区域(Region),虽然还保留新生代/老年代的概念,但是新生代和老年代不再是物理隔离,他们都是一部分Region(不连续)的集合。每个Region都有一个对应的”Remembered Set“用来避免进行全堆扫描,虚拟机发现程序对Reference 引用的对象进行写操作时没回产生一个 Write Barrier 暂时中断写操作,检查引用对象是否在别的Region中(分代收集器中就是检查老年代是否引用新生代对象)。如果存在就通过CardTable吧相关引用信息记录到被引用对象所属的Region 的Remembered Set中,在内存回收时,在根节点的枚举范围中加入Remem-Bered Set 即可保证不对全堆扫描,也不会遗漏。
    
    如果不算维护Remem-Bered Set 的操作,G1运行步骤分为     1.初始标记 2.并发标记  3.最终标记 4.筛选回收
    开始的运行步骤和CMS比较类似,
    ”初始标记“只是标记GC ROOTS 能直接关联的对象,并修改TAMS(Next Top at Mark Start)的值,让下阶段用户程序并发运行时能在正确可用的Region中创建新对象,需要停顿线程,但耗时很短。
    ”并发标记“从GC ROOT开始对堆对象进行可达性分析,找出存活对象,这阶段耗时较长,但是可以和用户线程并发执行
    ”最终标记“是为了修正并发标记旗舰变化的部分,虚拟机将对象变化的记录在线程Remembered Set Logs 中,最终标记是吧Remembered Set Logs  数据合并到Remembered Set 中,这阶段需要
停顿线程,也可以并行执行
   “筛选回收”阶段首先对各Region的回收价值和成本进行排序,根据用户期望的GC停顿时间制定回收计划,因为只回收一部分Region ,时间用户可控制,所以停顿用户线程将大幅度提高GC效率
 
 
运行图:
 
2016-09-01 谷占东 end
 
 
  • JVM

    JVM(Java Virtual Machine)Java 虚拟机是一个微型操作系统,有自己的硬件构架体系,还有相应的指令系统。能够识别 Java 独特的 .class 文件(字节码),能够将这些文件中的信息读取出来,使得 Java 程序只需要生成 Java 虚拟机上的字节码后就能在不同操作系统平台上进行运行。

    180 引用 • 120 回帖 • 3 关注
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3190 引用 • 8214 回帖 • 1 关注
  • 垃圾收集器
    1 引用 • 1 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • relyn

    涨姿势了

推荐标签 标签

  • Bootstrap

    Bootstrap 是 Twitter 推出的一个用于前端开发的开源工具包。它由 Twitter 的设计师 Mark Otto 和 Jacob Thornton 合作开发,是一个 CSS / HTML 框架。

    18 引用 • 33 回帖 • 667 关注
  • sts
    2 引用 • 2 回帖 • 197 关注
  • Solo

    Solo 是一款小而美的开源博客系统,专为程序员设计。Solo 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    1435 引用 • 10056 回帖 • 489 关注
  • Bug

    Bug 本意是指臭虫、缺陷、损坏、犯贫、窃听器、小虫等。现在人们把在程序中一些缺陷或问题统称为 bug(漏洞)。

    76 引用 • 1737 回帖 • 1 关注
  • OpenShift

    红帽提供的 PaaS 云,支持多种编程语言,为开发人员提供了更为灵活的框架、存储选择。

    14 引用 • 20 回帖 • 632 关注
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    107 引用 • 153 回帖
  • Notion

    Notion - The all-in-one workspace for your notes, tasks, wikis, and databases.

    7 引用 • 40 回帖
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖 • 1 关注
  • CongSec

    本标签主要用于分享网络空间安全专业的学习笔记

    1 引用 • 1 回帖 • 15 关注
  • WebComponents

    Web Components 是 W3C 定义的标准,它给了前端开发者扩展浏览器标签的能力,可以方便地定制可复用组件,更好的进行模块化开发,解放了前端开发者的生产力。

    1 引用 • 4 关注
  • jsoup

    jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API,可通过 DOM,CSS 以及类似于 jQuery 的操作方法来取出和操作数据。

    6 引用 • 1 回帖 • 483 关注
  • AngularJS

    AngularJS 诞生于 2009 年,由 Misko Hevery 等人创建,后为 Google 所收购。是一款优秀的前端 JS 框架,已经被用于 Google 的多款产品当中。AngularJS 有着诸多特性,最为核心的是:MVC、模块化、自动化双向数据绑定、语义化标签、依赖注入等。2.0 版本后已经改名为 Angular。

    12 引用 • 50 回帖 • 483 关注
  • SEO

    发布对别人有帮助的原创内容是最好的 SEO 方式。

    35 引用 • 200 回帖 • 27 关注
  • SSL

    SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS 与 SSL 在传输层对网络连接进行加密。

    70 引用 • 193 回帖 • 416 关注
  • 星云链

    星云链是一个开源公链,业内简单的将其称为区块链上的谷歌。其实它不仅仅是区块链搜索引擎,一个公链的所有功能,它基本都有,比如你可以用它来开发部署你的去中心化的 APP,你可以在上面编写智能合约,发送交易等等。3 分钟快速接入星云链 (NAS) 测试网

    3 引用 • 16 回帖 • 6 关注
  • Hadoop

    Hadoop 是由 Apache 基金会所开发的一个分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。

    86 引用 • 122 回帖 • 626 关注
  • WordPress

    WordPress 是一个使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设自己的博客。也可以把 WordPress 当作一个内容管理系统(CMS)来使用。WordPress 是一个免费的开源项目,在 GNU 通用公共许可证(GPLv2)下授权发布。

    66 引用 • 114 回帖 • 223 关注
  • Wide

    Wide 是一款基于 Web 的 Go 语言 IDE。通过浏览器就可以进行 Go 开发,并有代码自动完成、查看表达式、编译反馈、Lint、实时结果输出等功能。

    欢迎访问我们运维的实例: https://wide.b3log.org

    30 引用 • 218 回帖 • 635 关注
  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    23020 引用 • 92599 回帖
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    171 引用 • 512 回帖
  • 数据库

    据说 99% 的性能瓶颈都在数据库。

    343 引用 • 723 回帖
  • 服务

    提供一个服务绝不仅仅是简单的把硬件和软件累加在一起,它包括了服务的可靠性、服务的标准化、以及对服务的监控、维护、技术支持等。

    41 引用 • 24 回帖
  • 宕机

    宕机,多指一些网站、游戏、网络应用等服务器一种区别于正常运行的状态,也叫“Down 机”、“当机”或“死机”。宕机状态不仅仅是指服务器“挂掉了”、“死机了”状态,也包括服务器假死、停用、关闭等一些原因而导致出现的不能够正常运行的状态。

    13 引用 • 82 回帖 • 60 关注
  • 小说

    小说是以刻画人物形象为中心,通过完整的故事情节和环境描写来反映社会生活的文学体裁。

    28 引用 • 108 回帖
  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 75 关注
  • ActiveMQ

    ActiveMQ 是 Apache 旗下的一款开源消息总线系统,它完整实现了 JMS 规范,是一个企业级的消息中间件。

    19 引用 • 13 回帖 • 668 关注