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

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

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

    3169 引用 • 8207 回帖 • 1 关注
  • 垃圾收集器
    1 引用 • 1 回帖

相关帖子

欢迎来到这里!

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

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

    涨姿势了

推荐标签 标签

  • jQuery

    jQuery 是一套跨浏览器的 JavaScript 库,强化 HTML 与 JavaScript 之间的操作。由 John Resig 在 2006 年 1 月的 BarCamp NYC 上释出第一个版本。全球约有 28% 的网站使用 jQuery,是非常受欢迎的 JavaScript 库。

    63 引用 • 134 回帖 • 741 关注
  • NGINX

    NGINX 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 NGINX 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。

    311 引用 • 546 回帖 • 33 关注
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的操作系统上。容器完全使用沙箱机制,几乎没有性能开销,可以很容易地在机器和数据中心中运行。

    477 引用 • 901 回帖
  • SVN

    SVN 是 Subversion 的简称,是一个开放源代码的版本控制系统,相较于 RCS、CVS,它采用了分支管理系统,它的设计目标就是取代 CVS。

    29 引用 • 98 回帖 • 693 关注
  • 大疆创新

    深圳市大疆创新科技有限公司(DJI-Innovations,简称 DJI),成立于 2006 年,是全球领先的无人飞行器控制系统及无人机解决方案的研发和生产商,客户遍布全球 100 多个国家。通过持续的创新,大疆致力于为无人机工业、行业用户以及专业航拍应用提供性能最强、体验最佳的革命性智能飞控产品和解决方案。

    2 引用 • 14 回帖 • 3 关注
  • 音乐

    你听到信仰的声音了么?

    59 引用 • 509 回帖
  • 互联网

    互联网(Internet),又称网际网络,或音译因特网、英特网。互联网始于 1969 年美国的阿帕网,是网络与网络之间所串连成的庞大网络,这些网络以一组通用的协议相连,形成逻辑上的单一巨大国际网络。

    96 引用 • 330 回帖
  • webpack

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

    41 引用 • 130 回帖 • 292 关注
  • ZeroNet

    ZeroNet 是一个基于比特币加密技术和 BT 网络技术的去中心化的、开放开源的网络和交流系统。

    1 引用 • 21 回帖 • 593 关注
  • App

    App(应用程序,Application 的缩写)一般指手机软件。

    90 引用 • 383 回帖 • 1 关注
  • 小说

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

    28 引用 • 108 回帖
  • ReactiveX

    ReactiveX 是一个专注于异步编程与控制可观察数据(或者事件)流的 API。它组合了观察者模式,迭代器模式和函数式编程的优秀思想。

    1 引用 • 2 回帖 • 126 关注
  • Thymeleaf

    Thymeleaf 是一款用于渲染 XML/XHTML/HTML5 内容的模板引擎。类似 Velocity、 FreeMarker 等,它也可以轻易的与 Spring 等 Web 框架进行集成作为 Web 应用的模板引擎。与其它模板引擎相比,Thymeleaf 最大的特点是能够直接在浏览器中打开并正确显示模板页面,而不需要启动整个 Web 应用。

    11 引用 • 19 回帖 • 319 关注
  • 微信

    腾讯公司 2011 年 1 月 21 日推出的一款手机通讯软件。用户可以通过摇一摇、搜索号码、扫描二维码等添加好友和关注公众平台,同时可以将自己看到的精彩内容分享到微信朋友圈。

    129 引用 • 793 回帖 • 1 关注
  • Shell

    Shell 脚本与 Windows/Dos 下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比 Windows 下的批处理更强大,比用其他编程程序编辑的程序效率更高,因为它使用了 Linux/Unix 下的命令。

    122 引用 • 73 回帖
  • SMTP

    SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。

    4 引用 • 18 回帖 • 592 关注
  • Ubuntu

    Ubuntu(友帮拓、优般图、乌班图)是一个以桌面应用为主的 Linux 操作系统,其名称来自非洲南部祖鲁语或豪萨语的“ubuntu”一词,意思是“人性”、“我的存在是因为大家的存在”,是非洲传统的一种价值观,类似华人社会的“仁爱”思想。Ubuntu 的目标在于为一般用户提供一个最新的、同时又相当稳定的主要由自由软件构建而成的操作系统。

    123 引用 • 168 回帖
  • 阿里巴巴

    阿里巴巴网络技术有限公司(简称:阿里巴巴集团)是以曾担任英语教师的马云为首的 18 人,于 1999 年在中国杭州创立,他们相信互联网能够创造公平的竞争环境,让小企业通过创新与科技扩展业务,并在参与国内或全球市场竞争时处于更有利的位置。

    43 引用 • 221 回帖 • 237 关注
  • 面试

    面试造航母,上班拧螺丝。多面试,少加班。

    324 引用 • 1395 回帖 • 2 关注
  • wolai

    我来 wolai:不仅仅是未来的云端笔记!

    1 引用 • 11 回帖
  • 电影

    这是一个不能说的秘密。

    120 引用 • 597 回帖 • 1 关注
  • Sandbox

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

    370 引用 • 1215 回帖 • 582 关注
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1083 引用 • 3461 回帖 • 286 关注
  • CSDN

    CSDN (Chinese Software Developer Network) 创立于 1999 年,是中国的 IT 社区和服务平台,为中国的软件开发者和 IT 从业者提供知识传播、职业发展、软件开发等全生命周期服务,满足他们在职业发展中学习及共享知识和信息、建立职业发展社交圈、通过软件开发实现技术商业化等刚性需求。

    14 引用 • 155 回帖
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用 • 8 关注
  • AngularJS

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

    12 引用 • 50 回帖 • 427 关注