天天看點

8、記憶體管理機制---記憶體配置設定與回收政策

    對象的記憶體配置設定,一般就是在堆上配置設定空間,對象主要配置設定在新生代的Eden區上,如果啟動了本地線程配置設定緩沖,将按線程優先在TLAB(緩存)上配置設定。也可能會直接配置設定在老年代中,配置設定的規則并不是百分之百固定的,其細節取決于目前使用的是哪一種垃圾收集器組合,還有虛拟機中與記憶體相關的參數的設定。

1、對象優先在Eden配置設定

大多數情況下,對象在新生代Eden區中配置設定。當Eden區沒有足夠的空間進行配置設定時,虛拟機将發起一次Minor GC。

-xmn10M 為jvm的新生代空間;

-Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails -XX:SurvivorRatio=8 -Xloggc:D:/Documents/gc.log

public static void main(String...s) throws Exception{
		byte[] b1 = new byte[2 * 1024*1024];
		byte[] b2 = new byte[2 * 1024*1024];
		byte[] b3 = new byte[2 * 1024*1024];
		byte[] b4 = new byte[4 * 1024*1024];//超過了10m
	}
           

沒有出現異常,檢視gc日志:

0.082: [GC 0.082: [DefNew: 6692K->370K(9216K), 0.0028794 secs] 6692K->6514K(19456K), 0.0029189 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 def new generation   total 9216K, used 4794K [0x334f0000, 0x33ef0000, 0x33ef0000)
  eden space 8192K,  54% used [0x334f0000, 0x33941fa0, 0x33cf0000)
  from space 1024K,  36% used [0x33df0000, 0x33e4cb30, 0x33ef0000)
  to   space 1024K,   0% used [0x33cf0000, 0x33cf0000, 0x33df0000)
 tenured generation   total 10240K, used 6144K [0x33ef0000, 0x348f0000, 0x348f0000)
   the space 10240K,  60% used [0x33ef0000, 0x344f0030, 0x344f0200, 0x348f0000)
 compacting perm gen  total 12288K, used 146K [0x348f0000, 0x354f0000, 0x388f0000)
   the space 12288K,   1% used [0x348f0000, 0x34914a68, 0x34914c00, 0x354f0000)
    ro space 10240K,  45% used [0x388f0000, 0x38d77290, 0x38d77400, 0x392f0000)
    rw space 12288K,  54% used [0x392f0000, 0x3997ace8, 0x3997ae00, 0x39ef0000)
           

分析:

new generation(新生代):

          eden space 8192K =  10*1024kb  *80%

          form  space(survival) = 1024kb      ****這裡可用的空間大小為9*1024kb****

          to   space(survival) = 1024kb

tenured generation(老年代):

       space  10* 1024kb

執行main方法時,會發生minor gc 因為新生代需要的記憶體空間為10m而可用的空間是9m,而b1,b2,b3大小為2m比to space(1m)大,不能通過複制方法執行;此時gc隻能通過擔保機制将b1,b2,b3放入tenured generation中,這樣新生代可用空間又為9m了;

1.the space 10240K,  60% used

2.eden space 8192K,  54% used 

    from space 1024K,  36% used 

2、大對象直接進入老年代

       大對象就是指需要大量連續記憶體空間的Java對象,典型大對象:長字元串及數組。大對象對虛拟機的記憶體配置設定來說就是一個壞消息(遇到一群“朝生夕滅”的“短命大對象”,寫程式時應當避免),經常出現大對象容易導緻記憶體還有不少空間時就提前觸發垃圾收集以擷取足夠的連續空間來“安置”它們。

      虛拟機提供了一個-XX:PretenureSizeThreshold=3*1024*1024參數,令大于這個設定值的對象直接在老年代中配置設定。這樣做的目的是避免在Eden區及兩個Survivor區之間發生大量的記憶體拷貝

      PretenureSizeThreshold參數隻對Serial和ParNew兩款收集器有效,Parallel Scavenge收集器不認識這個參數,Parallel Scavenge收集器一般并不需要設定。如果遇到必須使用此參數的場合,可以考慮ParNew加CMS的收集器組合。

3、長期存活的對象将進入老年代

      記憶體回收時應該識别哪些對象應當放在新生代,哪些對象應放在老年代中。為了做到這點,虛拟機給每個對象定義了一個對象年齡(Age)計數器。如果對象在Eden出生并經過第一次Minor GC後仍然存活,并且能被Survivor容納的話,将被移動到Survivor空間中,并将對象年齡設為1。對象在Survivor區中每熬過一次Minor GC,年齡就增加1歲,當它的年齡增加到一定程度(預設為15歲)時,就會被晉升到老年代中。對象晉升老年代的年齡門檻值,可以通過參數-XX:MaxTenuringThreshold=15來設定。

4、 動态對象年齡判定

      為了能更好地适應不同程式的記憶體狀況,虛拟機并不總是要求對象的年齡必須達到MaxTenuringThreshold才能晉升老年代,如果在Survivor空間中相同年齡所有對象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對象就可以直接進入老年代,無須等到MaxTenuringThreshold中要求的年齡。

5、空間配置設定擔保

      在發生Minor GC時,虛拟機會檢測之前每次晉升到老年代的平均大小是否大于老年代的剩餘空間大小,如果大于,則改為直接進行一次Full GC。如果小于,則檢視HandlePromotionFailure設定是否允許擔保失敗;如果允許,那隻會進行Minor GC;如果不允許,則也要改為進行一次Full GC。大部分情況下都還是會将HandlePromotionFailure開關打開,避免Full GC過于頻繁。