1. 程式人生 > >JVM-GC總結-配置實戰--第三發

JVM-GC總結-配置實戰--第三發

配置舉例1:

vm args:
-Xms60m -Xmx60m -XX:NewRatio=2 -XX:SurvivorRatio=3 -XX:MaxPermSize=30m -XX:MaxTenuringThreshold=3 -XX:+PrintHeapAtGC

使用工具:jvisualvm (安裝visual gc 外掛)
這裡寫圖片描述
根據設定堆記憶體為60m, 因為設定了-XX:NewRatio=2所以年輕代與年老代的比例是1:2,
年輕代 20m,年老代40m, 設定-XX:SurvivorRatio=3 所以 survivor與eden的比例是1:3,
Eden佔年輕代的3/5是12m,s0,s1各佔1/5是4m,從圖中可以看到jvm記憶體分佈符合設定的引數,方法區(非堆)30m.
此時程式剛執行,dump了一下堆,可以看到剛生成的好多物件都是jmx相關的物件
這裡寫圖片描述

執行程式碼每次增加1m的物件到記憶體,當eden無法建立時會觸發一次minor gc,
這時由於survivor區無法承載eden中的全部物件,所以物件直接進入了老年代,
見圖:
這裡寫圖片描述
Eden中的物件一部分進入了s0,另一部分直接進入了年老代.
這裡寫圖片描述
上圖,再次增加物件到eden,觸發了一次minor gc,此時s1無法存放eden中的全部存活物件和s0中的存活物件, 老年代此時承擔了記憶體擔保的角色存放了多餘的物件.
這裡寫圖片描述
上圖中,由於程式中物件一直是存活的無法回收所以會一直進入老年代無法gc回收掉.

這裡寫圖片描述
上圖中老年代已滿無法繼續存放物件,此時full gc 有無法回收掉物件所以會報出

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
堆記憶體溢位,程式退出.
看一下最後一次gc時堆中前後的資料對比:
{Heap before GC invocations=9 (full 5):
 PSYoungGen      total 16384K, used 11264K [0x00000000fec00000, 0x0000000100000000, 0x0000000100000000)
  eden space 12288K, 91% used [0x00000000fec00000,0x00000000ff7001d0,0x00000000ff800000)
  from space 4096K, 0% used [0x00000000ffc00000,0x00000000ffc00000,0x0000000100000000)
  to
space 4096K, 0% used [0x00000000ff800000,0x00000000ff800000,0x00000000ffc00000) PSOldGen total 40960K, used 40572K [0x00000000fc400000, 0x00000000fec00000, 0x00000000fec00000) object space 40960K, 99% used [0x00000000fc400000,0x00000000feb9f1e0,0x00000000fec00000) PSPermGen total 21248K, used 8605K [0x00000000fa600000, 0x00000000fbac0000, 0x00000000fc400000) object space 21248K, 40% used [0x00000000fa600000,0x00000000fae677a0,0x00000000fbac0000) Heap after GC invocations=9 (full 5): PSYoungGen total 16384K, used 11264K [0x00000000fec00000, 0x0000000100000000, 0x0000000100000000) eden space 12288K, 91% used [0x00000000fec00000,0x00000000ff7001d0,0x00000000ff800000) from space 4096K, 0% used [0x00000000ffc00000,0x00000000ffc00000,0x0000000100000000) to space 4096K, 0% used [0x00000000ff800000,0x00000000ff800000,0x00000000ffc00000) PSOldGen total 40960K, used 40538K [0x00000000fc400000, 0x00000000fec00000, 0x00000000fec00000) object space 40960K, 98% used [0x00000000fc400000,0x00000000feb969f8,0x00000000fec00000) PSPermGen total 21248K, used 8537K [0x00000000fa600000, 0x00000000fbac0000, 0x00000000fc400000) object space 21248K, 40% used [0x00000000fa600000,0x00000000fae56550,0x00000000fbac0000) }

此次測試程式碼:

public class JConsoleTest {
    /**
     * 記憶體佔位符物件 大約64k
     */
    static class ConObj{

        public byte[] placeholder = new byte[1024 * 1024];
    }


    public static void fillHeap(int num) throws InterruptedException {
        List<ConObj> list = new ArrayList<ConObj>();
        for(int i = 0;i < num;i++){
            Thread.sleep(500);
            list.add(new ConObj());
        }

        //由於方法未執行完畢 list尚在作用域中 此時 執行gc 會導致回收不掉
        //System.gc();

    }
    /**
     * 設定例項:
     *   1)vm args:
     *    -Xms1024m -Xmx1024m -XX:NewRatio=4 -XX:SurvivorRatio=4  -XX:MaxPermSize=16m
     *
     *   2)vm args:
     *    -Xms60m -Xmx60m -XX:NewRatio=2 -XX:SurvivorRatio=3  -XX:MaxPermSize=30m -XX:MaxTenuringThreshold=3 -XX:+PrintHeapAtGC
     *
     * 演示jconsole的記憶體頁籤  觀察 eden survivor
     * vm args: -Xms100m -Xmx100m -XX:+UseSerialGC
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(30000);
        fillHeap(100);
        //可以回收掉
        System.gc();
        fillHeap(100);
        fillHeap(100);
        System.gc();
        synchronized (JConsoleTest.class){
            JConsoleTest.class.wait();
        }
    }
}

配置舉例2

  -Xmx60m -Xms60m -Xmn30m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC   -XX:MaxTenuringThreshold=3   -XX:+PrintGCApplicationStoppedTime -XX:+PrintHeapAtGC

這裡寫圖片描述

根據配置jvm堆大小為60m,其中分配給年輕代30m,年輕代中eden和s0,s1的比例預設是8:1, eden 24m,s0,s1各3m,
這裡寫圖片描述

上圖第一次觸發minor gc,同1老年代記憶體擔保承擔,很多物件沒有經過survivor直接進入了老年代
第一次minor gc的堆前後對比:

{Heap before GC invocations=0 (full 0):
 par new generation   total 27648K, used 24576K [0x00000000f7200000, 0x00000000f9000000, 0x00000000f9000000)
  eden space 24576K, 100% used [0x00000000f7200000, 0x00000000f8a00000, 0x00000000f8a00000)
  from space 3072K,   0% used [0x00000000f8a00000, 0x00000000f8a00000, 0x00000000f8d00000)
  to   space 3072K,   0% used [0x00000000f8d00000, 0x00000000f8d00000, 0x00000000f9000000)
 concurrent mark-sweep generation total 30720K, used 0K [0x00000000f9000000, 0x00000000fae00000, 0x00000000fae00000)
 concurrent-mark-sweep perm gen total 21248K, used 8687K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)
Heap after GC invocations=1 (full 0):
 par new generation   total 27648K, used 3007K [0x00000000f7200000, 0x00000000f9000000, 0x00000000f9000000)
  eden space 24576K,   0% used [0x00000000f7200000, 0x00000000f7200000, 0x00000000f8a00000)
  from space 3072K,  97% used [0x00000000f8d00000, 0x00000000f8fefd98, 0x00000000f9000000)
  to   space 3072K,   0% used [0x00000000f8a00000, 0x00000000f8a00000, 0x00000000f8d00000)
 concurrent mark-sweep generation total 30720K, used 8194K [0x00000000f9000000, 0x00000000fae00000, 0x00000000fae00000)
 concurrent-mark-sweep perm gen total 21248K, used 8687K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)
}   

第一次minor gc 應用暫停時間:
Total time for which application threads were stopped: 0.0215440 seconds – 21.5ms
這裡寫圖片描述
上圖是通過System.gc()觸發了一次full gc之後的jvm記憶體分佈.
下面是full gc 前後heap前後對比:

{Heap before GC invocations=1 (full 0):
 par new generation   total 27648K, used 17646K [0x00000000f7200000, 0x00000000f9000000, 0x00000000f9000000)
  eden space 24576K,  59% used [0x00000000f7200000, 0x00000000f804bb48, 0x00000000f8a00000)
  from space 3072K,  97% used [0x00000000f8d00000, 0x00000000f8fefd98, 0x00000000f9000000)
  to   space 3072K,   0% used [0x00000000f8a00000, 0x00000000f8a00000, 0x00000000f8d00000)
 concurrent mark-sweep generation total 30720K, used 8194K [0x00000000f9000000, 0x00000000fae00000, 0x00000000fae00000)
 concurrent-mark-sweep perm gen total 21248K, used 8703K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)
Heap after GC invocations=2 (full 1):
 par new generation   total 27648K, used 0K [0x00000000f7200000, 0x00000000f9000000, 0x00000000f9000000)
  eden space 24576K,   0% used [0x00000000f7200000, 0x00000000f7200000, 0x00000000f8a00000)
  from space 3072K,   0% used [0x00000000f8d00000, 0x00000000f8d00000, 0x00000000f9000000)
  to   space 3072K,   0% used [0x00000000f8a00000, 0x00000000f8a00000, 0x00000000f8d00000)
 concurrent mark-sweep generation total 30720K, used 923K [0x00000000f9000000, 0x00000000fae00000, 0x00000000fae00000)
 concurrent-mark-sweep perm gen total 21248K, used 8698K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)
}

應用暫停時間:
Total time for which application threads were stopped: 0.0292275 seconds – 29ms

繼續新增物件觸發minor gc
![這裡寫圖片描述](https://img-blog.csdn.net/201504231118209{Heap before GC invocations=2 (full 1):
par new generation total 27648K, used 24576K [0x00000000f7200000, 0x00000000f9000000, 0x00000000f9000000)
eden space 24576K, 100% used [0x00000000f7200000, 0x00000000f8a00000, 0x00000000f8a00000)
from space 3072K, 0% used [0x00000000f8d00000, 0x00000000f8d00000, 0x00000000f9000000)
to space 3072K, 0% used [0x00000000f8a00000, 0x00000000f8a00000, 0x00000000f8d00000)
concurrent mark-sweep generation total 30720K, used 923K [0x00000000f9000000, 0x00000000fae00000, 0x00000000fae00000)
concurrent-mark-sweep perm gen total 21248K, used 8711K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)
Heap after GC invocations=3 (full 1):
par new generation total 27648K, used 395K [0x00000000f7200000, 0x00000000f9000000, 0x00000000f9000000)
eden space 24576K, 0% used [0x00000000f7200000, 0x00000000f7200000, 0x00000000f8a00000)
from space 3072K, 12% used [0x00000000f8a00000, 0x00000000f8a62f30, 0x00000000f8d00000)
to space 3072K, 0% used [0x00000000f8d00000, 0x00000000f8d00000, 0x00000000f9000000)
concurrent mark-sweep generation total 30720K, used 923K [0x00000000f9000000, 0x00000000fae00000, 0x00000000fae00000)
concurrent-mark-sweep perm gen total 21248K, used 8711K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)
}or gc 回收了eden中的大部分物件.
程式暫停時間:
Total time for which application threads were stopped: 0.0039866 seconds
配置2程式碼:

public class JConsoleTest {
    /**
     * 記憶體佔位符物件 大約64k
     */
    static class ConObj{

        public byte[] placeholder = new byte[1024 * 1024];
    }
    public static void fillHeap(int num) throws InterruptedException {
        List<ConObj> list = new ArrayList<ConObj>();
        for(int i = 0;i < num;i++){
            Thread.sleep(500);
            list.add(new ConObj());
        }
        //由於方法未執行完畢 list尚在作用域中 此時 執行gc 會導致回收不掉
        //System.gc();

    }
    /**
     * 設定例項:
     *   1)vm args:
     *    -Xms1024m -Xmx1024m -XX:NewRatio=4 -XX:SurvivorRatio=4  -XX:MaxPermSize=16m
     *
     *   2)vm args:
     *    -Xms60m -Xmx60m -XX:NewRatio=2 -XX:SurvivorRatio=3  -XX:MaxPermSize=30m -XX:MaxTenuringThreshold=3 -XX:+PrintHeapAtGC
     *
     *   3) vm args:
     *      -Xmx60m -Xms60m -Xmn30m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC   -XX:MaxTenuringThreshold=3   -XX:+PrintGCApplicationStoppedTime -XX:+PrintHeapAtGC
     * 演示jconsole的記憶體頁籤  觀察 eden survivor
     * vm args: -Xms100m -Xmx100m -XX:+UseSerialGC
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(15000);
        fillHeap(20);
        //可以回收掉
        System.gc();
        fillHeap(20);
        fillHeap(5);
        fillHeap(20);
        System.gc();
        synchronized (JConsoleTest.class){
            JConsoleTest.class.wait();
        }
    }
}

上述是倆個較為簡單的jvm引數配置演示.