對象何時進入老年代、何時發生full gc


 

一、對象何時進入老年代

(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問題

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM