GCRoot
一个对象可以属于多个root,GC root有几下种:
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持有"的了。
Minor GC
当Eden区满了的时候会触发一次MinorGC,采用复制算法,将MinorGC后Eden区和Survivor区中还存活的对象复制到另一块空闲的survivor块上,也就是survivorTo,并将survivor区中存活的对象年龄加1,年龄到达一定大小就进入老年区,默认15,如果survivorTo也放不下的对象则直接进入老年代;MinorGC之后Eden区和一块surivor区会被清空
FullGC
- System.gc()方法的调用
方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率,也即增加了间歇性停顿的次数。
2、老年代空间不足
老年代空间只有在新生代对象转入及创建大对象、大数组时才会出现不足的现象,当执行Full GC后空间仍然不足,则抛出如下错误:
java.lang.OutOfMemoryError: Java heap space
为避免以上两种状况引起的Full GC,调优时应尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。
3、永生区空间不足
永久代
指永久的内存存放区域,主要存放class文件和Meta(元数据),比如类的层级信息,类的方法数据和方法信息,运行时常量池,已确定的符号引用h和虚方法表;class在被加载的时候被放入永久代,和存放的实例,
GC不会在主程序运行期间对永久代进行垃圾回收,这导致永久代随着类加载得class增多而胀满,触发OOM异常;
Java8已移除永久代,常量池也单独拉出来了,采用元数据区替代
元数据区是在Java8开始设计出来代替永久代的,Java8移除了永久代,但是元数据仍然还存在,元数据区不是在堆空间内,而是在一个和堆不相连的一个本地内存区域,这块区域就被称为元数据区
大小设置:
-XX:PermSize = 1024m,设置永久代的初始值
-XX:MaxPermSize = 1024m,设置永久代的最大值
永久代的垃圾回收:
垃圾回收不会发生在永久代,永久代满了或者超过了临界值,就会触发垃圾回收(Full GC),合理设置永久代大小能有效避免FullGC
条件:
该类的实例全部都被回收
加载该类的类加载器已经被回收
该类不能通过反射访问到其方法,而且该类的Java.lang.class没有被引用
4、CMS GC时出现promotion failed和concurrent mode failure
CMS使用一个叫做分配担保的机制,每次Minor GC之后要保证新生代的空间survivor + eden > 老年带的空闲时间,但是对象分配是不可预测的,总会有写对象分配在老年带是满足不了的。
- promotion failed – concurrent mode failure
Minor GC后, 救助空间容纳不了剩余对象,将要放入老年带,老年带有碎片或者不能容纳这些对象,就产生了concurrent mode failure, 然后进行stop-the-world的Serial Old收集器。
解决办法:-XX:UseCMSCompactAtFullCollection -XX:CMSFullGCBeforeCompaction=5 或者 调大新生代或者救助空间
- concurrent mode failure
CMS是和业务线程并发运行的,在执行CMS的过程中有业务对象需要在老年带直接分配,例如大对象,但是老年带没有足够的空间来分配,所以导致concurrent mode failure, 然后需要进行stop-the-world的Serial Old收集器。
解决办法:+XX:CMSInitiatingOccupancyFraction,调大老年带的空间,+XX:CMSMaxAbortablePrecleanTime
总结一句话:使用标记整理清除碎片和提早进行CMS操作。
5,堆中分配很大的对象
所谓大对象,是指需要大量连续内存空间的java对象,例如很长的数组,此种对象会直接进入老年代,而老年代虽然有很大的剩余空间,但是无法找到足够大的连续空间来分配给当前对象,此种情况就会触发JVM进行Full GC。
为了解决这个问题,CMS垃圾收集器提供了一个可配置的参数,即-XX:+UseCMSCompactAtFullCollection开关参数,用于在“享受”完Full GC服务之后额外免费赠送一个碎片整理的过程,内存整理的过程无法并发的,空间碎片问题没有了,但提顿时间不得不变长了,JVM设计者们还提供了另外一个参数 -XX:CMSFullGCsBeforeCompaction,这个参数用于设置在执行多少次不压缩的Full GC后,跟着来一次带压缩的