概述
ps:以前看的好多书,都忘了,决定好好写博客,写总结了
GC的问题大致分为三大类:
1.要gc哪些对象?
2.通过什么方法来gc?
3.什么时候触发gc?怎样gc的?
下面通过对这三个问题的思考来捋一捋gc相关的知识点:
一.要GC哪些对象?
通常来说,不使用的对象,就应该被回收,怎么找到不使用的对象呢?有两种算法:引用计数法,可达性分析法。对于java语言来说,由于循环引用的存在,因此引用计数法不可用。是通过可达性分析的方法去找到应该被回收的对象(不可达的对象)。
可达性分析:通过GCroots找到所有可达的对象,其余对象为不可达,并对其进行标记。但这一次标记的对象不一定全部被回收,如果实现了finialize()方法的对象会被放到F-quenu队列中,并执行finialize()自救,会对F-quenu中对象进行第二次标记,如果还是不可达,那么在GC的时候才会被回收。
二.通过什么方法来gc?
gc主要针对于jvm内存区的堆进行垃圾回收,对于垃圾回收的方法有三种主流算法:
- 复制
- 标记-清除
- 标记-整理
复制算法,实现简单,效率高,但需要多一倍内存。
标记-清楚算法,实现简单,效率不高,且容易发生浮动垃圾,但不需要多一倍内存。
标记-整理算法,实现复杂,效率最低,但不回有浮动垃圾产生,也不需要多一倍内存
对于大多数对象来说,都是频繁的或者,频繁的死去,因此jvm采用分代的机制把堆分为了年轻代和老年代。年轻代采用复制算法,年老代采用(标记-清楚)或者(标记-整理),具体要看老年代的垃圾回收器。
三.什么时候GC?是怎样GC的?
3.1 什么时候GC?
jvm根据堆的划分,把gc大致分为了minorGc和fullGc,当然对于不同的垃圾回收器的实现还有不同的gc方式。
minorGc:
年轻代Gc,当Eden区满了后,就会发生minorGc,采用的是复制算法,把Eden区和S0区的剩余对象放到S1区中。这过程中有三个个细节:
1.如果一个对象在年轻代被GC的次数超过了设置的阀值,这个对象就会放到老年代中。
2.如果年轻代中相同年龄的对象大小的总和大于Survior区的一半,那么大于等于这个年龄的对象也会放到老年代中。
3.如果Eden区和from区剩余的对象存放到to区中,如果还有对象放不下剩余,这些对象就会加入到老年代。
对象进入老年代的四种情况:
1.如果Eden区和from区剩余的对象存放到to区中,如果还有对象放不下剩余,这些对象就会加入到老年代。
2.如果是大对象,直接放到老年代中。
3.在新生代中,年龄超过设置阀值的对象会晋升到老年代。
4.根据动态年龄判定,在新生代中有一半年龄超过某个值,那这一半都会晋升到老年代中
FullGc:整个堆和方法区进行Gc,有多个触发条件:
- 1.显示调用System.gc()方法。
- 2.minorGc后统计要晋升的对象大小大于老年代剩余的空间大小。就触发FullGc。
- 3.在cms收集器并发清理阶段,也会产生垃圾,因此如果产生的垃圾,不能进入老年代,会触发concurrent-mode-failure 或者 晋升失败的情况,这时候会触发full gc
- 4.方法区Perm空间不足。
除了minorGc和FullGc还有两种特殊的gc,cms垃圾回收器特有的oldgc 和 g1垃圾回收器特有的mixedGc。
oldGc:当老年代的对象数量多于cms设置的阀值,就触动oldGc,回收老年代中的对象,但是cms是基于并发-清除算法的,因此会产生很多浮动垃圾。当浮动垃圾过多时,导致触发fullGc,是调用SerialOld执行fullGc。
mixedGc:当g1垃圾收集器的全局并发标记的对象数量多于g1通过G1HeapWastePercent参数,在global
concurrent marking结束之后,我们可以知道old gen
regions中有多少空间要被回收,在每次YGC之后和再次发生Mixed
GC之前,会检查垃圾占比是否达到此参数,只有达到了,下次才会发生Mixed GC。
3.2 各个垃圾收集器是怎么GC的?
java中垃圾收集器分为3类:
- 串行垃圾收集器:就是单线程的垃圾收集器Serial、SerialOld
- 并行垃圾收集器:多个g1线程一起进行垃圾收集 ParallelScavenge、ParallelOld(优化吞吐量)
- 并发垃圾收集器:CMS、G1 垃圾收集器(减少停顿时间)
这里并发是垃圾收集器线程和用户线程并发执行。即gc的过程中,用户线程并不是完全停止。
评判一个垃圾收集器的好坏的两个标准:
- 停顿时间:垃圾收集器做垃圾回收中断应用程序执行的时间。
- 吞吐量:垃圾回收的时间和花在应用程序的占比。
下面来重点介绍一下两个并发垃圾收集器:
简单说一下CMS和G1垃圾收集器
cms和g1 同样都是并发垃圾收集器,都可以在垃圾收集的过程中用户线程并发执行。
cms垃圾收集器是只作用在老年代的垃圾收集器,且其中的垃圾回收算法是采用标记-清除算法的。cms的gc过程是:
- 初始标记 (stop the world)这次标记只标记和Gcroots直接关联的对象。
- 并发标记 这次标记用户线程也在执行,gc线程标记gcroots路径上的对象。
- 并发预清理 (这一步和重新标记是一样的,但是是并发的,此阶段标记从新生代晋升的对象、新分配到老年代的对象以及在并发阶段被修改了的对象,在这个阶段,可能会触发一次minorGC)
- 重新标记 (stop the world)标记并发标记过程中,产生的新对象
- 并发清除 用户线程和gc线程并发处理
由于cms采用的标记-清除算法,会产生大量的浮动垃圾,可能会导致“current-mode-failure”和晋升失败,触发Fullgc
g1垃圾收集器是作用在真个堆中的,这有别于其他所有的垃圾收集器,g1垃圾收集器虽然也有分代的概念,但实际上,它把内存分为多个region区域。
gc过程是:
- 触发youngGc条件后,开始全局并发标记
- 初始标记
- 并发标记
- 重新标记
- 清楚垃圾
上面全局并发标记的步骤和cms基本一样,但是在重新标记后,会检查堆中垃圾是否达到G1HeapWastePercent设置的阀值,如果设置了,就开始mixedGc,否则只进行youngGc。
另外,一旦触发了fullgc,实际也是由serialOld执行fullgc。
从局部看,g1GC采用的是复制算法,从整体看采用的是标记-整理算法.
最后
以上就是文静小海豚为你收集整理的GC相关问题一.要GC哪些对象?三.什么时候GC?是怎样GC的? 的全部内容,希望文章能够帮你解决GC相关问题一.要GC哪些对象?三.什么时候GC?是怎样GC的? 所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复