垃圾收集器與內(nèi)存分配策略(四)——內(nèi)存分配回收策略

對象的內(nèi)存分配鼎姐,往大方向講绊起,就是在堆上分配(但也可能經(jīng)過JIT編譯后被拆分為標量類型并間接地在棧上分配)械蹋,對象主要分配在新生代的Eden區(qū)上暑始,如果啟動了本地線程分配緩沖涉瘾,將按線程優(yōu)先在TLAB上分配蓝仲。少數(shù)情況下也可能會直接分配在老年代中烙心,分配的規(guī)則并不是百分百固定的凭峡,其細節(jié)取決于當前使用的是哪一種垃圾收集器我抠,還有虛擬機中與內(nèi)存有關的參數(shù)設置苇本。
下面是在測試時使用client模式,試驗環(huán)境jdk 1.6.0_37菜拓,驗證使用Serial/Serial Old收集器下的內(nèi)存分配和回收策略瓣窄。

一、對象優(yōu)先在Eden分配

  • 大多數(shù)情況下纳鼎,對象在新生代Eden區(qū)中分配俺夕。當Eden區(qū)沒有足夠空間進行分配時,虛擬機將發(fā)起一次Minor GC贱鄙。
  • Minor GC和Full GC(Major GC)區(qū)別:Minor GC是指發(fā)生在新生代的垃圾收集動作劝贸,因為Java對象大多具備朝生夕滅的特定,所以Minor GC非常頻繁贰逾,一般回收速度也比較快悬荣。Full GC是指發(fā)生在老年代的GC,出現(xiàn)了Major GC疙剑,經(jīng)常會伴隨至少一次的Minor GC(但并非絕對氯迂,Parellel Scavenge收集器策略可選擇直接進行Major GC的策略),Major GC的速度一般比Minor GC慢10倍以上言缤,所以應該減少觸發(fā)的次數(shù)嚼蚀。
/**
     * VM參數(shù):-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
     * 限制java堆大小為20M,年輕代為10M管挟,Eden為8M轿曙,兩個survivor分別為1M
      */
    
    public static void testAllocation() {
        byte[] allocation1, allocation2, allocation3, allocation4;
        allocation1 = new byte[2 * _1MB];
        allocation2 = new byte[2 * _1MB];
        allocation3 = new byte[2 * _1MB];
        allocation4 = new byte[4 * _1MB];  // 出現(xiàn)一次Minor GC
        
        
        /**
        [GC [DefNew: 6487K->152K(9216K), 0.0040116 secs] 6487K->6296K(19456K), 0.0040436 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
        Heap
         def new generation   total 9216K, used 4576K [0x32750000, 0x33150000, 0x33150000)
          eden space 8192K,  54% used [0x32750000, 0x32ba1fa8, 0x32f50000)
          from space 1024K,  14% used [0x33050000, 0x33076150, 0x33150000)
          to   space 1024K,   0% used [0x32f50000, 0x32f50000, 0x33050000)
         tenured generation   total 10240K, used 6144K [0x33150000, 0x33b50000, 0x33b50000)
           the space 10240K,  60% used [0x33150000, 0x33750030, 0x33750200, 0x33b50000)
         compacting perm gen  total 12288K, used 376K [0x33b50000, 0x34750000, 0x37b50000)
           the space 12288K,   3% used [0x33b50000, 0x33bae2c0, 0x33bae400, 0x34750000)
            ro space 10240K,  55% used [0x37b50000, 0x380d1140, 0x380d1200, 0x38550000)
            rw space 12288K,  55% used [0x38550000, 0x38bf44c8, 0x38bf4600, 0x39150000)
         * 
         */
     }

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

  • 所謂的大對象是指需要大量連續(xù)內(nèi)存空間的Java對象僻孝,最典型的大對象就是那種很長的字符串以及數(shù)組导帝。大對象對虛擬機的內(nèi)存分配來說就是一個壞消息(程序員應該避免寫那種朝生夕滅的短命大對象),經(jīng)常出現(xiàn)大對象容易導致內(nèi)存還有不少就提前觸發(fā)垃圾收集器以獲取足夠的連續(xù)空間來“安置”它們穿铆。
  • 虛擬機提供了一個-XX:PretenureSizeThreshold參數(shù)您单,令大于這個設置值的對象直接在老年代分配。這樣做的目的是避免在Eden去以及兩個Survivor區(qū)之間發(fā)生大量的內(nèi)存復制荞雏。
    /**
     * VM參數(shù):-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=3145728
     * 對象超過3M 時直接進入老年代
     */
    public static void testPretenureSizeThreshold() {
        byte[] allocation;
        allocation = new byte[4 * _1MB];  //直接分配在老年代中
        
        /**
 Heap
 def new generation   total 9216K, used 507K [0x32750000, 0x33150000, 0x33150000)
  eden space 8192K,   6% used [0x32750000, 0x327cef38, 0x32f50000)
  from space 1024K,   0% used [0x32f50000, 0x32f50000, 0x33050000)
  to   space 1024K,   0% used [0x33050000, 0x33050000, 0x33150000)
 tenured generation   total 10240K, used 4096K [0x33150000, 0x33b50000, 0x33b50000)
   the space 10240K,  40% used [0x33150000, 0x33550010, 0x33550200, 0x33b50000)
 compacting perm gen  total 12288K, used 376K [0x33b50000, 0x34750000, 0x37b50000)
   the space 12288K,   3% used [0x33b50000, 0x33bae3b8, 0x33bae400, 0x34750000)
    ro space 10240K,  55% used [0x37b50000, 0x380d1140, 0x380d1200, 0x38550000)
    rw space 12288K,  55% used [0x38550000, 0x38bf44c8, 0x38bf4600, 0x39150000)
          
          
          
         */
    }

三虐秦、長期存活對象進入老年代

  • 對象在兩個survivor區(qū)每復制(Minor gc)一次平酿,年齡就增長一歲,當超過指定最大隨時時轉(zhuǎn)移到老年代中悦陋。
  • -XX:MaxTenuringThreshold=8 參數(shù)用于設定對象最大年齡閾值蜈彼,分別設置為8和1運行的結果是不一樣的。
/**
     * VM參數(shù):-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=1 -XX:+PrintTenuringDistribution
     * 
     */
    @SuppressWarnings("unused")
    public static void testTenuringThreshold() {
        byte[] allocation1, allocation2, allocation3;
        allocation1 = new byte[_1MB / 4];  //262144 什么時候進入老年代決定于XX:MaxTenuringThreshold設置
        allocation2 = new byte[4 * _1MB]; //4194304
        allocation3 = new byte[4 * _1MB];
        allocation3 = null;
        allocation3 = new byte[4 * _1MB];
        /**
         * 
         * XX:MaxTenuringThreshold =8
         [GC [DefNew
Desired survivor size 524288 bytes, new threshold 8 (max 8)
- age   1:     418144 bytes,     418144 total
: 4695K->408K(9216K), 0.0036693 secs] 4695K->4504K(19456K), 0.0036983 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC [DefNew
Desired survivor size 524288 bytes, new threshold 8 (max 8)
- age   1:        136 bytes,        136 total
- age   2:     417936 bytes,     418072 total
: 4668K->408K(9216K), 0.0010034 secs] 8764K->4504K(19456K), 0.0010296 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 def new generation   total 9216K, used 4668K [0x32750000, 0x33150000, 0x33150000)
  eden space 8192K,  52% used [0x32750000, 0x32b78fe0, 0x32f50000)
  from space 1024K,  39% used [0x32f50000, 0x32fb6118, 0x33050000)
  to   space 1024K,   0% used [0x33050000, 0x33050000, 0x33150000)
 tenured generation   total 10240K, used 4096K [0x33150000, 0x33b50000, 0x33b50000)
   the space 10240K,  40% used [0x33150000, 0x33550010, 0x33550200, 0x33b50000)
 compacting perm gen  total 12288K, used 377K [0x33b50000, 0x34750000, 0x37b50000)
   the space 12288K,   3% used [0x33b50000, 0x33bae5b8, 0x33bae600, 0x34750000)
    ro space 10240K,  55% used [0x37b50000, 0x380d1140, 0x380d1200, 0x38550000)
    rw space 12288K,  55% used [0x38550000, 0x38bf44c8, 0x38bf4600, 0x39150000)
         
         */
        
        /**
         * 
         * XX:MaxTenuringThreshold=1
         [GC [DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 1)
- age   1:     418144 bytes,     418144 total
: 4695K->408K(9216K), 0.0054252 secs] 4695K->4504K(19456K), 0.0054708 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
[GC [DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 1)
- age   1:        136 bytes,        136 total
: 4668K->0K(9216K), 0.0013601 secs] 8764K->4504K(19456K), 0.0013867 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 def new generation   total 9216K, used 4260K [0x32750000, 0x33150000, 0x33150000)
  eden space 8192K,  52% used [0x32750000, 0x32b78fe0, 0x32f50000)
  from space 1024K,   0% used [0x32f50000, 0x32f50088, 0x33050000)
  to   space 1024K,   0% used [0x33050000, 0x33050000, 0x33150000)
 tenured generation   total 10240K, used 4504K [0x33150000, 0x33b50000, 0x33b50000)
   the space 10240K,  43% used [0x33150000, 0x335b60a0, 0x335b6200, 0x33b50000)
 compacting perm gen  total 12288K, used 377K [0x33b50000, 0x34750000, 0x37b50000)
   the space 12288K,   3% used [0x33b50000, 0x33bae5c0, 0x33bae600, 0x34750000)
    ro space 10240K,  55% used [0x37b50000, 0x380d1140, 0x380d1200, 0x38550000)
    rw space 12288K,  55% used [0x38550000, 0x38bf44c8, 0x38bf4600, 0x39150000)
         
         
         */
    }

四俺驶、對象動態(tài)年齡判斷

  • 雖然可以設置對象最大年齡閾值幸逆,但有時候虛擬機會根據(jù)內(nèi)存情況自己動態(tài)計算對象的閾值。
    當survivor區(qū)相同年齡的大小不小于survivor區(qū)的一半時痒钝,虛擬機會把survivor區(qū)等于和大于此年齡的對象轉(zhuǎn)移到老年代秉颗。
/**
     * VM參數(shù):-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15  -XX:+PrintTenuringDistribution
     * 
     */
    @SuppressWarnings("unused")
    public static void testTenuringThreshold2() {
        byte[] allocation1, allocation2, allocation3, allocation4;
        allocation1 = new byte[_1MB / 4];   // allocation1+allocation2大于survivo空間一半
        allocation2 = new byte[_1MB / 4];  
        allocation3 = new byte[4 * _1MB];
        allocation4 = new byte[4 * _1MB];
        allocation4 = null;
        allocation4 = new byte[4 * _1MB];
        
        /**
         * [GC [DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 15)
- age   1:     680304 bytes,     680304 total
: 4951K->664K(9216K), 0.0033210 secs] 4951K->4760K(19456K), 0.0033442 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC [DefNew
Desired survivor size 524288 bytes, new threshold 15 (max 15)
- age   1:        136 bytes,        136 total
: 4924K->0K(9216K), 0.0011772 secs] 9020K->4760K(19456K), 0.0011987 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 def new generation   total 9216K, used 4260K [0x32750000, 0x33150000, 0x33150000)
  eden space 8192K,  52% used [0x32750000, 0x32b78fe0, 0x32f50000)
  from space 1024K,   0% used [0x32f50000, 0x32f50088, 0x33050000)
  to   space 1024K,   0% used [0x33050000, 0x33050000, 0x33150000)
 tenured generation   total 10240K, used 4760K [0x33150000, 0x33b50000, 0x33b50000)
   the space 10240K,  46% used [0x33150000, 0x335f60b0, 0x335f6200, 0x33b50000)
 compacting perm gen  total 12288K, used 377K [0x33b50000, 0x34750000, 0x37b50000)
   the space 12288K,   3% used [0x33b50000, 0x33bae5c0, 0x33bae600, 0x34750000)
    ro space 10240K,  55% used [0x37b50000, 0x380d1140, 0x380d1200, 0x38550000)
    rw space 12288K,  55% used [0x38550000, 0x38bf44c8, 0x38bf4600, 0x39150000)
         */
    }

解釋:
new threshold 1 (max 15) 表示 虛擬機自己計算的閾值為1 ,最大15送矩。

五、空間分配擔保

  • 在發(fā)送minor gc之前哪替,虛擬機會首先檢查老年代最大可連續(xù)空間是否大于新生代所有對象總和栋荸,如果這個條件成立,可以確保這次minor gc是安全的凭舶, 如果不成立晌块,虛擬機會查看HandlePromotionFailure設置值是否允許擔保失敗。如果允許帅霜,那么會繼續(xù)檢查老年代最大可連續(xù)空間是否大于歷次晉升到老年代對象的評價大小匆背,如果大于,將嘗試一次minor gc身冀,盡管這次minor gc是有風險的钝尸;如果小于,或者HandlePromotionFailure設置不允許冒險搂根,那么這時也要改為一次Full gc珍促。
  • 在jdk1.6 update24之后,HandlePromotionFailure參數(shù)不會影響虛擬機空間分配擔保策略剩愧,虛擬機改為猪叙,只要老年代最大連續(xù)空間大于新生代對象總和或者大于歷次晉升平均大小,都將進行minor gc仁卷,否則將進行Full gc穴翩。
/**
     * VM參數(shù):-Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:-HandlePromotionFailure
     */
    @SuppressWarnings("unused")
    public static void testHandlePromotion() {
        byte[] allocation1, allocation2, allocation3, allocation4, allocation5, allocation6, allocation7;
        allocation1 = new byte[2 * _1MB];
        allocation2 = new byte[2 * _1MB];
        allocation3 = new byte[2 * _1MB];
        allocation1 = null;
        allocation4 = new byte[2 * _1MB];
        allocation5 = new byte[2 * _1MB];
        allocation6 = new byte[2 * _1MB];
        allocation4 = null;
        allocation5 = null;
        allocation6 = null;
        allocation7 = new byte[2 * _1MB];
        
        /**
         * 
        
        java.version = 1.6.0_37
        
        
        [GC [DefNew: 6487K->152K(9216K), 0.0040346 secs] 6487K->4248K(19456K), 0.0040639 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC [DefNew: 6546K->152K(9216K), 0.0004896 secs] 10642K->4248K(19456K), 0.0005141 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 def new generation   total 9216K, used 2364K [0x32750000, 0x33150000, 0x33150000)
  eden space 8192K,  27% used [0x32750000, 0x32978fe0, 0x32f50000)
  from space 1024K,  14% used [0x32f50000, 0x32f76108, 0x33050000)
  to   space 1024K,   0% used [0x33050000, 0x33050000, 0x33150000)
 tenured generation   total 10240K, used 4096K [0x33150000, 0x33b50000, 0x33b50000)
   the space 10240K,  40% used [0x33150000, 0x33550020, 0x33550200, 0x33b50000)
 compacting perm gen  total 12288K, used 377K [0x33b50000, 0x34750000, 0x37b50000)
   the space 12288K,   3% used [0x33b50000, 0x33bae758, 0x33bae800, 0x34750000)
    ro space 10240K,  55% used [0x37b50000, 0x380d1140, 0x380d1200, 0x38550000)
    rw space 12288K,  55% used [0x38550000, 0x38bf44c8, 0x38bf4600, 0x39150000)
Warning: The flag -HandlePromotionFailure has been EOL'd as of 6.0_24 and will be ignored
         */
    }
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市锦积,隨后出現(xiàn)的幾起案子芒帕,更是在濱河造成了極大的恐慌,老刑警劉巖充包,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件副签,死亡現(xiàn)場離奇詭異遥椿,居然都是意外死亡,警方通過查閱死者的電腦和手機淆储,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門冠场,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人本砰,你說我怎么就攤上這事碴裙。” “怎么了点额?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長载慈。 經(jīng)常有香客問我,道長寡具,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任撰豺,我火速辦了婚禮亩歹,結果婚禮上小作,老公的妹妹穿的比我還像新娘。我一直安慰自己静秆,他們只是感情好扶认,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布叠纹。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪款慨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天,我揣著相機與錄音颗圣,去河邊找鬼。 笑死屁使,一個胖子當著我的面吹牛在岂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蛮寂,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蔽午,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了酬蹋?” 一聲冷哼從身側響起及老,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤抽莱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后骄恶,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體食铐,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年叠蝇,在試婚紗的時候發(fā)現(xiàn)自己被綠了璃岳。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡悔捶,死狀恐怖铃慷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蜕该,我是刑警寧澤犁柜,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站堂淡,受9級特大地震影響馋缅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜绢淀,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一萤悴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧皆的,春花似錦覆履、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至楞抡,卻和暖如春伟众,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背召廷。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工凳厢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人柱恤。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓数初,卻偏偏與公主長得像,于是被迫代替她去往敵國和親梗顺。 傳聞我的和親對象是個殘疾皇子泡孩,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354