新生代
回收算法
通过复制算法实现垃圾的回收,将标记被使用的对象复制到一个未存放对象的空间,然后清空当前空间中的剩余对象。因此复制清除算法需要一块单独的空闲空间用于对象的复制。
可用GC
- 串行GC
- parallel scavenge(PS):并行回收
- 采用复制算法
- 扫描和复制都是多线程执行
- 根据新生代回收情况,动态调整eden、s0、s1的大小
- 适合于多核CPU的机器,server级别默认采用的回收方式(cpu核数超过2、内存大小超过2G)
- parnew:并行
- 跟上面的PS都是采用多线程的方式对新生代进行回收
- 跟上面的PS的区别在于必须配合老年代的CMS GC使用,因为CMS进行垃圾回收的时候,有写过程需要并发执行,如果此时发生新生代回收(对象需要移动到老年代),需要新生代做一些特殊的处理,但是上面的PS新生代回收没有这部分的特殊处理,也正是因为parnew的这部分特殊处理,因此parnew不能与老年代的并行GC一起使用
进入老年代
- 年轻代每次垃圾回收都会给未回收的对象的年龄+1,对象的年龄超过一定限制之后,会被移动到老年代
- 新生代进行垃圾回收的时候,需要复制到s区的对象的大小如果超过了s区的空间大小,那么超出的对象会被移动到老年代
- 对象创建的时候,如果对象的大小过大,会直接在老年代中进行创建
老年代
回收算法
- 标记清除
- 标记整理
可用GC
- 串行GC:生产环境基本不太会使用
- 并行GC:采用标记整理算法
- CMS:并发标记清除
- 回收过程
- 初始标记:暂停整个应用
- 并发标记
- 重新标记:暂停整个应用
- 并发清除
- 采用free list的方式进行内存的分配,因此在分配的时候不能像bump-the-point方式那样从某个位置开始分配对象即可,需要查找free list找到能放得下该对象的空间,因此一定程度上会减慢新生代的垃圾回收速度(新生代回收之后,如果s区域放不下,需要将对象放入老年代)
- 并发回收过程中可能出现的并发问题,==这个还不是特别明白==
- 并发标记过程中,新生代回收可能造成老年代对象引用关系的变化,避免这种问题是通过
Mod Union Table
来记录新生代回收造成的引用关系变化 - 并发标记过程中,可能应用修改了老年代中对象之间的引用关系,采用Card Table的方式进行了记录
- 并发标记过程中,新生代回收可能造成老年代对象引用关系的变化,避免这种问题是通过
- 触发时机
- 老年代使用空间超过设定的百分比,默认是68%,CMSInitiatingOccupancyFraction参数
- JVM自动触发,根据之前GC的频率,以及老年代的增长趋势来评估下次GC的时间,UseCMSInitiatingOccupancyOnly=true
- 回收过程
FullGC
正常情况下,JVM运行过程中,会经常进行年轻代的GC,生命周期较长的对象会被移动到老年代,当老年代占用的空间超过一定比例,会进行老年代的GC,由于老年代一般是用CMS等并发垃圾回收器,所以老年代的GC过程中,大部分时间是跟程序并发执行的,造成的程序的停顿时间很短,整个GC过程,基本上对程序的影响很少。
但是有几种情况会造成FullGC的执行,FullGC会触发年轻代的GC和老年代的GC,由于年轻代的GC很快,所以几乎可以忽略,所以FullGC几乎等价于老年代的GC。
- HotSpot VM的GC里,除了CMS的concurrent collection之外,其它能收集old gen的GC都会同时收集整个GC堆,包括young gen,所以对于CMS之外的老年代回收和FullGC实际上是等价的;至于为什么回收老年代的时候一起进行新生代的回收,因为young GC会尽量清理了young gen的死对象,减少了full GC的工作量
- Old GC:只收集old gen的GC。只有CMS的concurrent collection是这个模式,正常情况下,老年代占用空间超过一定的比例就回触发CMS,所以正常情况下,老年代的空间是够用的,不会触发FullGC,一旦出现FullGC,说明老年代的的CMS的回收速度跟不上了,需要排查原因
- Mixed GC:收集整个young gen以及部分old gen的GC。只有G1有这个模式
触发FullGC的情况主要有:
- 老年代空间不足
- 方法区空间不足
- 通过Minor GC后进入老年代的平均大小大于老年代的可用内存
- 由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小,此时CMS GC会出现promotion failed和concurrent mode failure
- 调用System.gc时,系统建议执行Full GC,但是不必然执行,或者说不一定什么时候执行
参考
- Major GC和Full GC的区别是什么?触发条件呢?
- 『分布式Java应用基础与实践』