关于CMS收集器的一点疑问。

当并发标记完之后要进行重新标记。那么并发标记的意义是什么?直接重新标记不就完了?
还有标记清除算法。如果清除后剩余的存活对象之间连续的内存不够分配给下一个对象,会OOM吗?
CMS为什么要有一个初始标记的过程呢,而不是直接并发标记?
求解惑,谢谢。

全部评论
首先CMS是一个old gen收集器。 initial mark阶段需要找到所有的GC roots,这个阶段会STW,GC roots选取比较快,所以停顿时间不会太长。 concurrent mark阶段,GC roots tracing,扫描整个heap上(包括young gen和old gen)的所有存活的对象,这个阶段是和用户线程并发执行的,用户线程感知不到停顿。 remark阶段,需要修正在concurrent mark阶段发生变化的引用关系,具体就是young gen有新的对象加入,需要扫描整个young gen,修正引用关系,这个阶段需要STW,CMS最长的停顿时间在这个阶段,young gen越大,停顿时间越长(CMS之前可先跑一次young GC,降低remark阶段停顿时间)。 concurrent sweep阶段:并发清除。 CMS用的是mark sweep算法,会有内存碎片,如果CMS GC之后old gen仍然无法分配,就会启动backup的serial old进行full GC。平时CMS GC old gen跑到一定的容量的时候,也会用serial old跑一次full GC。
点赞 回复 分享
发布于 2017-09-03 21:55
并发标记期间,用户程序也在运行吖,它有可能会对已经标记过的某些对象的标记记录产生影响,所以要重新标记。 标记清除后,内存不够分配下一个对象的话,会再次触发新的垃圾收集动作吧,再不够的话就OOM。哈哈,个人理解,不知道对不对。
点赞 回复 分享
发布于 2017-09-03 20:53
对于初始标记、并发标记、重新标记,我的理解是,初始标记只是JVM标记GC Roots能够直接关联的对象(直接关联应该是直接引用的对象),所以“Stop the world”;并发标记时进行 GC Root Tracing,也就是查看哪些对象是可达的,所以GC线程和用户线程并行运行;重新标记是用来标记在并发标记过程中由于程序运行产生的变动对象,也需要“Stop the world”。
点赞 回复 分享
发布于 2017-09-03 21:16
借楼问一下CMS为什么要有一个初始标记的过程呢,而不是直接并发标记?
点赞 回复 分享
发布于 2017-09-03 20:58
对于第二个问题我的想法是,并发清除后的内存是不规整的,所以在为需要连续存储空间的大对象(数组或很大的字符串)分配空间时,会因为找不到连续的空间而触发一次GC。对于不需要连续存储空间的对象来说,JVM可以使用“空闲列表”来分配内存,所以不会触发GC。
点赞 回复 分享
发布于 2017-09-03 21:01
初始标记:把根搜索算法里的根对象标记出来,这个过程是stop the world的。 并发标记:并发的标记从根对象出发能引用到的所有对象,这个过程是不阻塞用户线程的。 再次标记:在并发标记过程中,可能对象的引用状态发生了变化,再检查一遍,这个过程stop the world。 垃圾回收:回收标记为垃圾的对象。 上面是自己的理解,下边是粘的: 根对象: 虚拟机栈(栈帧中的本地变量表)中的引用对象 本地方法栈中引用的对象 方法区中类静态属性引用的对象 方法区中常量引用的对象
点赞 回复 分享
发布于 2017-09-03 21:20
首先每一种算法都是有其需求的。之所以出现CMS算法,是希望尽可能减少GC过程对正常程序的影响。而这个影响来源于STW(stop the world),因为要清除无用的对象必须要在正常程序对这些对象无操作的情况下进行,否则可能出差错。 所以CMS算法把这个查询过程分了3步,其中第二步(tracing)是最费时间的,为了减少STW,第二步采用并发的模式进行,即不影响正常程序,这也就是为什么CMS算法采用分时标记的原因
点赞 回复 分享
发布于 2017-09-03 21:55

相关推荐

忙碌的香菇在秋招:两页不看,下一个
点赞 评论 收藏
分享
求个公司要我:接好运
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务