java基础---JVM---CMS垃圾回收器
====简述CMS垃圾回收器垃圾回收的几个流程
CMS作用于老年代的垃圾回收,但是也会扫描新生代的内容
1.初始标记阶段。用户线程暂停,标记所有和根对象直接相连的对象。
2.并发标记阶段。用户线程起来,这个阶段标记所有可到达的对象
3.预处理阶段。因为用户线程起来了,所以可能有修改对象或者新增的对象,这个阶段就是标记从新生代转移到老年代的对象,老年代新分配到的对象以及修改的对象等等。
因为下一个阶段是重标记,必须做GC停顿来扫描新生代和老年代,如何让这个停顿时间少,如何更快的扫描标记,就是本阶段的任务,所以预处理对新生代和老年代都做了相应的处理。
-----预处理阶段新生代的处理方式:1.进行minorGC 2.remark阶段会并发扫描新生代,所以预处理会将新生代分块,分别给多个线程处理这就是并发。
-----预处理阶段老年代的处理方式:1.使用Card Table加速扫描,是一个字节数组。老年代分块,每一块关联card table中一个字节。1.如果在并发标记阶段对象被用户线程修改了,就会标记成dirty card,预处理阶段进行可达性标记,然后把dirty card标记清除,这样并发标记阶段修改的对象也会被标记;2.如果老年代引用到新生代,也可以通过cardTable快速扫描到。
4.重标记阶段。暂停用户线程,重新标记可到达对象。预处理后这个阶段速度会加快。
5.并发清理的阶段。用户线程同时进行执行,产生新的垃圾。
6.重置。准备下个阶段的垃圾回收。
===CMS会带来什么问题呢?
1.并发的问题
CMS默认使用的GC线程数量为(CPU+3)/4,如果cpu数量少的时候比如只有两个,就会有1个进行GC那么应用就会有百分50的性能下降会很明显,但是当cpu数量上升的时候就不会有这种问题了。
2.并发的第二个问题。gc线程用户线程同步执行,就会有浮动垃圾产生。同时需要给用户线程提供执行的空间,也就是说不能等到老年代满了才进行垃圾回收,默认是到达百分92进行老年代垃圾回收。当然这个参数是可以设置的。太小了会使得gc频繁就会有停顿,太大了可能会导致用户线程无法执行,因为需要的空间不够,这个时候会导致使用串行回收器进行回收,停顿时间会更长。
3.标记清楚法带来的问题:内存碎片,可能老年代剩余空间很大但是因为内存碎片的原因,没有很大的连续内存空间,大对象进来可能就会触发垃圾回收。CMS的解决方式是通过设置在进行几次回收之后进行内存压缩。
====如果要标记老年代的对象,需要扫描新生代吗?如何加快新生代的扫描呢?预处理的阶段如何控制呢?
要标记老年代的对象需要扫描新生代,要想加快新生代的扫描就要让新生代里面的对象变少,也就是进行一次垃圾回收。
预处理阶段因为用户线程也在跑,那么对象会一直变化,总得要有个停下来的时候,这个时候可以设置参数让它停下来。