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

本贴最后更新于 2881 天前,其中的信息可能已经物是人非
该文简述了常用垃圾收集器的特点与区别,内容主要来自《深入理解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 回帖 • 1 关注
  • Java

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

    3169 引用 • 8208 回帖
  • 垃圾收集器
    1 引用 • 1 回帖

相关帖子

欢迎来到这里!

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

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

    涨姿势了

推荐标签 标签

  • 安全

    安全永远都不是一个小问题。

    191 引用 • 813 回帖 • 1 关注
  • ZooKeeper

    ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby 一个开源的实现,是 Hadoop 和 HBase 的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

    59 引用 • 29 回帖 • 10 关注
  • BookxNote

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖
  • C

    C 语言是一门通用计算机编程语言,应用广泛。C 语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

    83 引用 • 165 回帖 • 5 关注
  • flomo

    flomo 是新一代 「卡片笔记」 ,专注在碎片化时代,促进你的记录,帮你积累更多知识资产。

    4 引用 • 91 回帖
  • 国际化

    i18n(其来源是英文单词 internationalization 的首末字符 i 和 n,18 为中间的字符数)是“国际化”的简称。对程序来说,国际化是指在不修改代码的情况下,能根据不同语言及地区显示相应的界面。

    7 引用 • 26 回帖
  • CentOS

    CentOS(Community Enterprise Operating System)是 Linux 发行版之一,它是来自于 Red Hat Enterprise Linux 依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码,因此有些要求高度稳定的服务器以 CentOS 替代商业版的 Red Hat Enterprise Linux 使用。两者的不同在于 CentOS 并不包含封闭源代码软件。

    238 引用 • 224 回帖
  • ngrok

    ngrok 是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。

    7 引用 • 63 回帖 • 613 关注
  • 锤子科技

    锤子科技(Smartisan)成立于 2012 年 5 月,是一家制造移动互联网终端设备的公司,公司的使命是用完美主义的工匠精神,打造用户体验一流的数码消费类产品(智能手机为主),改善人们的生活质量。

    4 引用 • 31 回帖 • 8 关注
  • Mac

    Mac 是苹果公司自 1984 年起以“Macintosh”开始开发的个人消费型计算机,如:iMac、Mac mini、Macbook Air、Macbook Pro、Macbook、Mac Pro 等计算机。

    164 引用 • 594 回帖
  • 大数据

    大数据(big data)是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

    89 引用 • 113 回帖
  • IBM

    IBM(国际商业机器公司)或万国商业机器公司,简称 IBM(International Business Machines Corporation),总公司在纽约州阿蒙克市。1911 年托马斯·沃森创立于美国,是全球最大的信息技术和业务解决方案公司,拥有全球雇员 30 多万人,业务遍及 160 多个国家和地区。

    16 引用 • 53 回帖 • 130 关注
  • 一些有用的避坑指南。

    69 引用 • 93 回帖
  • Tomcat

    Tomcat 最早是由 Sun Microsystems 开发的一个 Servlet 容器,在 1999 年被捐献给 ASF(Apache Software Foundation),隶属于 Jakarta 项目,现在已经独立为一个顶级项目。Tomcat 主要实现了 JavaEE 中的 Servlet、JSP 规范,同时也提供 HTTP 服务,是市场上非常流行的 Java Web 容器。

    162 引用 • 529 回帖
  • FlowUs

    FlowUs.息流 个人及团队的新一代生产力工具。

    让复杂的信息管理更轻松、自由、充满创意。

    1 引用
  • webpack

    webpack 是一个用于前端开发的模块加载器和打包工具,它能把各种资源,例如 JS、CSS(less/sass)、图片等都作为模块来使用和处理。

    41 引用 • 130 回帖 • 283 关注
  • Hexo

    Hexo 是一款快速、简洁且高效的博客框架,使用 Node.js 编写。

    21 引用 • 140 回帖 • 12 关注
  • Sandbox

    如果帖子标签含有 Sandbox ,则该帖子会被视为“测试帖”,主要用于测试社区功能,排查 bug 等,该标签下内容不定期进行清理。

    386 引用 • 1226 回帖 • 593 关注
  • Pipe

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

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

    131 引用 • 1114 回帖 • 137 关注
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    495 引用 • 1386 回帖 • 329 关注
  • Flume

    Flume 是一套分布式的、可靠的,可用于有效地收集、聚合和搬运大量日志数据的服务架构。

    9 引用 • 6 回帖 • 613 关注
  • Vim

    Vim 是类 UNIX 系统文本编辑器 Vi 的加强版本,加入了更多特性来帮助编辑源代码。Vim 的部分增强功能包括文件比较(vimdiff)、语法高亮、全面的帮助系统、本地脚本(Vimscript)和便于选择的可视化模式。

    28 引用 • 66 回帖 • 7 关注
  • 分享

    有什么新发现就分享给大家吧!

    245 引用 • 1776 回帖 • 1 关注
  • H2

    H2 是一个开源的嵌入式数据库引擎,采用 Java 语言编写,不受平台的限制,同时 H2 提供了一个十分方便的 web 控制台用于操作和管理数据库内容。H2 还提供兼容模式,可以兼容一些主流的数据库,因此采用 H2 作为开发期的数据库非常方便。

    11 引用 • 54 回帖 • 648 关注
  • 负能量

    上帝为你关上了一扇门,然后就去睡觉了....努力不一定能成功,但不努力一定很轻松 (° ー °〃)

    88 引用 • 1234 回帖 • 441 关注
  • 尊园地产

    昆明尊园房地产经纪有限公司,即:Kunming Zunyuan Property Agency Company Limited(简称“尊园地产”)于 2007 年 6 月开始筹备,2007 年 8 月 18 日正式成立,注册资本 200 万元,公司性质为股份经纪有限公司,主营业务为:代租、代售、代办产权过户、办理银行按揭、担保、抵押、评估等。

    1 引用 • 22 回帖 • 706 关注
  • C++

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

    106 引用 • 152 回帖