java gc --- 关键词解释

分代gc

java的堆内存主要分为young generation与old generation,这两块分开回收。这就是所谓的分代gc

其中young generation又分为一个eden space与两个survivor space(From与To)。默认情况下,eden space占young generation的80%,两个survivor space各占10%。

young gc:新对象一般在eden space中分配,如果eden space满了,就进行一次。eden space + From 中的所有存活对象会被复制到To里去(这是因为大部分的新分配对象都会迅速死亡,每个survivor space虽然只占young generation的10%,但是一般情况下足够存放young gc中的存活元素)。每次young gc之后,From与To交换。

每个Object的对象头里都有字段用于记录这个对象经历了多少次young gc。如果一个对象熬过了一定次数(可以通过-XX:MaxTenuringThreshold配置,默认为15次)的Young gc而不死,那么可以晋升到old generation。

如果新对象的体积过大(可以通过-XX:PretenureSizeThreshold配置,但是该设置只对Serial和ParNew收集器生效),那么它会被直接分配到old generation

full gc:如果old generation也满了,就会触发full gc。full gc会对整个堆空间做gc。具体的操作是从gc root(下文介绍)出发,遍历所有可达对象,然后回收所有不可达对象。正常情况下会回收大量的内存,如果full gc后还是无法获得足够分配对象的内存,就会抛出OOM错误。

 一般来说young gc的耗时较少(数十或者数百毫秒级别),full gc耗时较长(一般在秒级别,如果堆内存很大,甚至可以产生分钟级别的停顿)

 

gc root

gc的起点,一组可以保证绝对存活的对象,例如:

Class - 由系统类加载器(system class loader)加载的对象,这些类是不能够被回收的,他们可以以静态字段的方式保存持有其它对象。我们需要注意的一点就是,通过用户自定义的类加载器加载的类,除非相应的java.lang.Class实例以其它的某种(或多种)方式成为roots,否则它们并不是roots,.
Thread - 活着的线程
Stack Local - Java方法的local变量或参数
JNI Local - JNI方法的local变量或参数
JNI Global - 全局JNI引用
Monitor Used - 用于同步的监控对象
Held by JVM - 用于JVM特殊目的由GC保留的对象,但实际上这个与JVM的实现是有关的。可能已知的一些类型是:系统类加载器、一些JVM知道的重要的异常类、一些用于处理异常的预分配对象以及一些自定义的类加载器等。然而,JVM并没有为这些对象提供其它的信息,因此就只有留给分析分员去确定哪些是属于"JVM持有"的了。

 

remember set/card table/write barrier

重新考虑上文提到的young gc,我们怎样才能知道young gen中的哪些对象是可达的?

最朴素的思想当然是从gc root出发,对整个heap中的对象进行可达性分析。这毫无疑问可以解决问题,但是如果这样做,young gc和full gc又有什么区别呢?

所以我们需要额外的机制来记录,old gen中的哪些对象引用了young gen中的对象。也可以理解为扩充了young gc中gc root的范围。

Remembered Set是在实现部分垃圾收集(partial GC)时用于记录从非收集部分指向收集部分的指针的集合的抽象数据结构。

card table是remember set的一种实现,card table实际上是一个byte数组,card table中的每个byte(也就是所谓的card)都对应了old gen中的一小块内存(chunk,默认是512byte)。如果card table中的某个card被标记为dirty,那么这个card对应的chunk中可能存在指向young gen的对象。在young gc时,就只需要扫描gc root + old gen中的dirty chunk中的对象即可。

card table的维护是由write barrier来完成的。任何对old gen中对象的修改,都会导致这个对象所在的chunk对应的card被标记为dirty。

card table的维护会带来一定的开销,但是根据统计分析,它确实可以极大的减少young gc的开销,所以还是值得的。

 

stw

stop the world,顾名思义,jvm中的所有工作线程都会暂停。此时整个java进程处于无响应状态。

young gc与full gc都会引起stw,只是时间长短的区别

 

promotion guarantee check

本节的讨论基于CMS算法

每次Minor GC执行完以后,虚拟机会检查之前晋升到老年代的平均大小是否大于老年代的剩余空间大小,如果大于,则发起一次Full/Major GC,如果小于,则查看HandlePromotionFailure值是否允许担保失败,如果允许,那只会进行一次Minor GC。如果不允许失败,那么也要改为进行一次Full/Major GC

如果young gc时,To的空间不足以存放From + Eden中的存活对象,那么这些对象会被直接移动到old gen中(即使它们的年龄还不足以提升到old gen,这个情况叫做premature promotion,中文大概叫“过早提升”,它会导致full gc频率提高,jvm虽然尽力优化,但还是无法避免)。如果此时old gen的空间也不足,就会引发Promtion failed。Promtion failed会引发full gc。

 

concurrent mode failure

Concurrent Mode Failure
The CMS collector uses one or more garbage collector threads that run simultaneously with the application threads with the goal of completing the collection of the tenured generation before it becomes full. As described previously, in normal operation, the CMS collector does most of its tracing and sweeping work with the application threads still running, so only brief pauses are seen by the application threads. However, if the CMS collector is unable to finish reclaiming the unreachable objects before the tenured generation fills up, or if an allocation cannot be satisfied with the available free space blocks in the tenured generation, then the application is paused and the collection is completed with all the application threads stopped. The inability to complete a collection concurrently is referred to as concurrent mode failure and indicates the need to adjust the CMS collector parameters. If a concurrent collection is interrupted by an explicit garbage collection (System.gc()) or for a garbage collection needed to provide information for diagnostic tools, then a concurrent mode interruption is reported.

1. 如果old gen在被用完前不能完成对无引用对象的回收。

2. 如果old gen中的剩余空间不能满足应用的内存分配需求。

上面这两个场景会引发Concurrent Mode Failure,此时old gen的收集器会从CMS切换到Serial Old,这会引起一次有非常长的stw的full gc

 

参考资料

http://hllvm.group.iteye.com/group/topic/21468#post-272070   RednaxelaFX对card table的说明

http://blog-archive.griddynamics.com/2011/06/understanding-gc-pauses-in-jvm-hotspots.html   card table + 分代gc

https://blogs.msdn.microsoft.com/abhinaba/2009/03/02/back-to-basics-generational-garbage-collection/   微软对card table的说明

http://dept.cs.williams.edu/~freund/cs434/hotspot-gc.pdf  card table + 分代gc

https://www.yourkit.com/docs/java/help/gc_roots.jsp  gc root都有什么?

http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html  oracle官方的gc调优文档

https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/cms.html   oracle官方对cms的说明

posted @ 2017-03-21 18:20  qeDVuHG  阅读(877)  评论(0编辑  收藏  举报