一、对象何时进入老年代
(1)当对象首次创建时, 会放在新生代的eden区, 若没有GC的介入,会一直在eden区, GC后,是可能进入survivor区或者年老代
(2)当对象年龄达到一定的大小 ,就会离开年轻代, 进入老年代。 而对象的年龄是由GC的次数决定的
-XX:MaxTenuringThreshold=n 新生代的对象最多经历n次GC, 就能晋升到老年代, 但不是必要条件
-XX:TargetSurvivorRatio=n 用于设置Survivor区的目标使用率,即当survivor区GC后使用率超过这个值, 就可能会使用较小的年龄作为晋升年龄
(3)除年龄外, 对象体积也会影响对象的晋升的, 若对象体积太大, 新生代无法容纳这个对象
-XX:PretenureSizeThreshold 即对象的大小大于此值, 就会绕过新生代, 直接在老年代分配, 此参数只对串行回收器以及ParNew回收有效, 而对ParallelGC回收器无效
二、何时发生full gc
public class ConcurrentMarkSweep { private static final int SIZE= 1024 * 1024; public static void main(String[] args) throws Exception{ byte[] a1, a2, a3, a4; a1 = new byte[2 * SIZE]; a2 = new byte[2 * SIZE]; a3 = new byte[2 * SIZE]; a4 = new byte[2 * SIZE]; System.in.read(); } }
1. System.gc()方法的调用
system.gc(), 此方法的调用是建议JVM进行Full GC, 可通过通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。
2. old/Tenured 空间不足
老年代空间在新生代对象转入及创建为大对象、大数组时
当执行Full GC后空间仍然不足,报错:java.lang.OutOfMemoryError: Java heap space
java -Xmx10m -Xms10m -Xmn10m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=75 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC gc.ConcurrentMarkSweep
3. perm/metaspace 空间不足
JVM规范中运行时数据区域中的方法区,在HotSpot虚拟机中又被习惯称为永生代或者永生区,
Permanet Generation中存放的为一些class的信息、常量、静态变量等数据,当系统中要加载的类、反射的类和调用的方法较多时,
当Full GC后空间仍然不足,报错:java.lang.OutOfMemoryError: PermGen space
java -cp .:/Users/gl/IntelliJProjects/JBase/jdk/build/tmp/lib/javassist-3.20.0-GA.jar -XX:MaxMetaspaceSize=32M gc.Metaspace
在我的MAC上,大约生成21165个class: Exception in thread "main" javassist.CannotCompileException: by java.lang.OutOfMemoryError: Metaspace
public class Metaspace { static ClassPool cp = ClassPool.getDefault(); public static void main(String[] args) throws Exception{ for (int i = 0; ; i++) { System.out.println(i); CtClass ctClass = cp.makeClass("com.mp.Person" + i ); //添加属性 ctClass.addField(CtField.make("private int age;", ctClass)); //添加setAge方法 ctClass.addMethod(CtMethod.make("public void setAge(int age){this.age = age;}", ctClass)); ctClass.addMethod(CtMethod.make("public int getAge(){return this.age;}", ctClass)); //If the program is running on some application server, the context class loader might be inappropriate to load the class. //如果没有调用,则没影响 ctClass.toClass(); } } }
4. CMS GC时出现promotion failed和concurrent mode failure
promotion failed是在进行Minor GC时,survivor space放不下, 对象只能放入老年代,而此时老年代也放不下造成的;
concurrent mode failure是在执行CMS GC的过程中同时有对象要放入老年代,而此时老年代空间不足造成的
java -Xmx10m -Xms10m -Xmn10m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=75 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC gc.ConcurrentMarkSweep
5. 判断当前新生代的对象是否能够全部顺利的晋升到老年代,如果不能,就提早触发一次老年代的收集
java -Xmx14m -Xms14m -Xmn10m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=75 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC ConcurrentMarkSweep
# JVM 通过 CMSInitiatingOccupancyFraction 的值确定是否gc
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=75
如下,Meta space 使用为达到75%, 却一直在发生FGC
如果永久代设置的很小,则会发生系统刚启动就执行CMS
参考:
占小狼:一个有意思的CMS问题