从前文JVM垃圾回收几种常见算法和常见收集器我们知道,CMS是老年代垃圾收集器。CMS 收集器主要关注系统停顿时间。CMS 是 Concurrent Mark Sweep 的缩写,意为并发标记清除,从名称上可以得知,它使用的是标记-清除算法,同时它又是一个使用多线程并发回收的垃圾收集器。它可以与Serial收集器和parNew收集器搭配使用。

    CMS工作时,主要步骤有:初始标记、并发标记、重新标记、并发清除和并发重置。其中初始标记和重新标记是独占系统资源的,而并发标记、并发清除和并发重置是可以和用户线程一起执行的。因此,从整体上来说,CMS收集不是独占式的,它可以在应用程序运行过程中进行垃圾回收。

根据标记-清除算法,初始标记、并发标记和重新标记都是为了标记出需要回收的对象。并发清理则是在标记完成后,正式回收垃圾对象;并发重置是指在垃圾回收完成后,重新初始化CMS数据结构和数据,为下一次垃圾回收做好准备。

CMS收集器在其主要的工作阶段虽然没有暴力地彻底暂停应用程序线程,但是由于它和应用程序线程并发执行,相互抢占CPU,所以在CMS执行期内对应用程序吞吐量造成一定影响。CMS 默认启动的线程数是 (ParallelGCThreads+3)/4),ParallelGCThreads 是新生代并行收集器的线程数,也可以通过-XX:ParallelCMSThreads参数手工设定CMS的线程数量。当CPU资源比较紧张时,受到CMS收集器线程的影响,应用程序的性能在垃圾回收阶段可能会非常糟糕。

由于CMS收集器不是独占式的回收器,在CMS回收过程中,应用程序仍然在不停地工作。在应用程序工作过程中,又会不断地产生垃圾。这些新生成的垃圾在当前CMS回收过程中是无法清除的。同时,因为应用程序没有中断,所以在CMS回收过程中,还应该确保应用程序有足够的内存可用。因此,CMS收集器不会等待堆内存饱和时才进行垃圾回收,而是当前堆内存使用率达到某一阈值时,便开始进行回收,以确保应用程序在CMS工作过程中依然有足够的空间支持应用程序运行。这个回收阈值可以使用-XX:CMSInitiatingOccupancyFraction来指定,默认是 68。即当老年代的空间使用率达到 68%时,会执行一次CMS回收。如果应用程序的内存使用率增长很快,在CMS的执行过程中,已经出现了内存不足的情况,此时CMS回收将会失败,JVM将启动老年代串行收集器进行垃圾回收。如果这样,应用程序将完全中断,直到垃圾收集完成,这时,应用程序的停顿时间可能很长。因此,根据应用程序的特点,可以对-XX:CMSInitiatingOccupancyFraction 进行调优。如果内存增长缓慢,则可以设置一个稍大的值,大的阈值可以有效降低CMS的触发频率,减少老年代回收的次数可以较为明显地改善应用程序性能。反之,如果应用程序内存使用率增长很快,则应该降低这个阈值,以避免频繁触发老年代串行收集器。    标记-清除算法将会造成大量内存碎片,离散的可用空间无法分配较大的对象。在这种情况下,即使堆内存仍然有较大的剩余空间,也可能会被迫进行一次垃圾回收,以换取一块可用的连续内存,这种现象对系统性能是相当不利的。为了解决这个问题,CMS收集器还提供了几个用于内存压缩整理的算法。

  • -XX:+UseCMSCompactAtFullCollection 使CMS在垃圾收集完成后,进行一次内存碎片整理。内存碎片的整理并不是并发进行的。

  • -XX:CMSFullGCsBeforeCompaction 用于设定进行多少次CMS回收后,进行一次内存整理。

  • -XX:+CMSScavengeBeforeRemark 最终标记之前强制进行一个Minor GC。

  • -XX:+UseConcMarkSweepGC 可以要求新生代使用parNew,老年代使用CMS。

  • -XX:+UseCMSInitiatingOccupancyOnly 

    指定CMSInitiatingOccupancyFraction的回收阈值,如果不指定,jvm仅在第一次使用设定值,后续则自动调整。

  • -XX:+CMSParallelRemarkEnabled 并行运行最终标记阶段,加快最终标记的速度

  • -XX:+CMSClassUnloadingEnabled 让CMS可以收集永久带,默认不会收集

  • -XX:+ExplicitGCInvokesConcurrent 当调用System.gc()的时候,执行并行gc,只有在CMS或者G1下该参数才有效

CMS对CPU的资源非常敏感。由于采用标记-清除算法会存在空间碎片的问题,导致大对象无法分配空间不得不提前触发一次full gc的情况。而且无法处理浮动垃圾,可能出现Concurrent Model Failure失败而导致另一次full gc的情况。

垃圾回收篇幅过长,下文继续讲解最后的内容G1收集器。

JVM垃圾回收之CMS收集器的更多相关文章

  1. JVM垃圾回收算法 及 垃圾收集器

    摘自<深入理解Java虚拟机> 一.什么是: GC算法是 方法论,那么垃圾收集器就是具体的 实现. 二.四种 垃圾回收算法 1.标记-清除算法:最基础的收集算法:不足有两点:1标记和清除两 ...

  2. JVM垃圾回收机制总结(3) :按代垃圾收集器

    为什么要分代 分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的 . 因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率. 在Java程序运行的过程中,会产生大量的对 ...

  3. JVM垃圾回收算法(最全)

    JVM垃圾回收算法(最全) 下面是JVM虚拟机运行时的内存模型: 1.方法区 Perm(永久代.非堆) 2.虚拟机栈 3.本地方法栈 (Native方法) 4.堆 5.程序计数器 1 首先的问题是:j ...

  4. Java虚拟机四:垃圾回收算法与垃圾收集器

    在Java运行时的几个数据区域中,程序计数器,虚拟机栈,本地方法栈3个区域随着线程而生,随线程而灭,因此这几个区域的内存分配和回收具有确定性,不需要过多考虑垃圾回收问题,因为方法结束或者线程结束时,内 ...

  5. JVM垃圾回收算法及回收器详解

    引言 本文主要讲述JVM中几种常见的垃圾回收算法和相关的垃圾回收器,以及常见的和GC相关的性能调优参数. GC Roots 我们先来了解一下在Java中是如何判断一个对象的生死的,有些语言比如Pyth ...

  6. Java:JVM垃圾回收(GC)机制

    JVM垃圾回收算法 1.标记清除(Mark-Sweep) 原理: 从根集合节点进行扫描,标记出所有的存活对象,最后扫描整个内存空间并清除没有标记的对象(即死亡对象)适用场合: 存活对象较多的情况下比较 ...

  7. JVM垃圾回收(GC)

    JVM垃圾回收(GC) 1. 判断对象是否可以被回收 引用计数法:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收.此方法简单,但无法解决对象相互循环引用的问 ...

  8. JVM学习记录3--垃圾收集器

    贴个图 Serial收集器 最简单的收集器,单线程,收集器会暂停用户线程,称为"stop the world". ParNew收集器 Serial收集器的多线程版本,其它类似.默认 ...

  9. A7. JVM 垃圾回收收集器(GC 收集器)

    [概述] 如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现.Java 虚拟机规范中对垃圾收集器应该如何实现没有任何规定,因此不同的厂商.不同版本的虚拟机所提供的垃圾处理器都可能会 ...

随机推荐

  1. 四十六:数据库之Flask-SQLAlchemy的使用

    一:连接数据库1.安装:pip install flask-sqlalchemy2.将数据库信息更新到app.config['SQLALCHEMY_DATABASE_URI']3.使用flask_sq ...

  2. linux下mongodb程序和c++客户端的编译

    2016-4-6     14:17:15   安装前准备:1/ 安装boost库2/ 安装scons程序 方法一:$ git clone git://github.com/mongodb/mongo ...

  3. js在页面中添加一个元素 —— 添加弹幕

    参考地址 [往下拉 —— 使用HTML DOM appendChild() 方法实现元素的添加 ] 一.创建 HTML <div class="right_liuyan"&g ...

  4. 从git上pull下的代码,执行时提示:ModuleNotFoundError: No module named '......',解决方法如下:

    方法一: 如果没有安装,如下: 1.PyCharm : file-> setting->Project interpreter–>package2.右侧有个+ 点击3.进入后 搜索p ...

  5. python学习之数据类型(tuple)

    3.6 元组 v = (11,22,33,'asd','汉字') 元组就是不可变的列表,又叫制度列表,属性特征与字符串相似,里边可以存放任何类型的元素. 1.元组的元素 这里元组的不可变的意思是⼦元素 ...

  6. 【机器学习】Linear least squares, Lasso,ridge regression有何本质区别?

    Linear least squares, Lasso,ridge regression有何本质区别? Linear least squares, Lasso,ridge regression有何本质 ...

  7. flaskurl传参用法

    from flask import Flask,request app = Flask(__name__) @app.route("/") def index(): return ...

  8. spring配置添加多个事务(转)

    大多数项目只需要一个事务管理器.然而,有些项目为了提高效率.或者有多个完全不同又不相干的数据源,最好用多个事务管理器.机智的Spring的Transactional管理已经考虑到了这一点,首先分别定义 ...

  9. Luogu P3953 [NOIP2017]逛公园

    题目 首先我们跑出从\(1\)出发的最短路\(d1\)和反图上从\(n\)出发的最短路\(dn\). 然后我们处理出长度不超过\(d1_n+k\)的最短路边集,给它拓扑排序. 如果存在环,那么这个环一 ...

  10. AppCan打包问题

    在AppCan IDEA打包的时候出了错误, Failed reading value of registry key: Software\JavaSoft\Java Runtime Environm ...