今天的內(nèi)容主要是內(nèi)存的分配遗嗽,其實前面已經(jīng)介紹了很多志鞍,就當作是復(fù)習(xí)吧。
大家現(xiàn)在應(yīng)該都知道了家乘,JAVA虛擬機在堆中存放對象實例蝗羊,所以對象的內(nèi)存分配也主要是在堆上進行。
堆中又分新生代和老年代(有疑問的可以看一下以前的文章)仁锯,對于新創(chuàng)建的對象耀找,按照對象的大小,
大的對象直接進入老年代业崖,小的對象進入新生代涯呻。
新生代一般又有兩類區(qū)域,Eden區(qū)和Survivor區(qū)腻要,Survivor區(qū)是用來存放垃圾收集后的存活對象的,
新創(chuàng)建的對象自然是進入Eden區(qū)涝登,當Eden區(qū)沒有足夠區(qū)域的時候?qū)⑦M行一次垃圾回收雄家。
下面讓我們用代碼來驗證一下。
首先在IDEA的DEBUG Configuration中增加虛擬機的一些設(shè)置胀滚。
然后編寫測試代碼如下趟济,
這里有一點需要注意,當最后沒有設(shè)置-XX:+UseSerialGC參數(shù)的時候咽笼,運行程序顷编,如下圖所示,發(fā)現(xiàn)ParOldGen中并沒有內(nèi)存占用剑刑。
原來默認情況下的JDK8的新生代使用的Parallel Scavenge收集器媳纬,在該收集器下-XX:PretenureSizeThreshold參數(shù)是無效的,
所以這里設(shè)置-XX:+UseSerialGC施掏,指定使用Serial垃圾收集器钮惠。
根據(jù)前幾篇的內(nèi)容,我們在參數(shù)中設(shè)置了堆的初始內(nèi)存和最大內(nèi)存都是90M七芭,新生代(占1/3)和老年代(占2/3)應(yīng)該分別占27M和60M素挽,并且按照默認情況就應(yīng)該是Eden:From Survivor:To Survivor為24M:3M:3M。
到底是不是這樣呢狸驳,再次運行程序(方法1)预明。
程序結(jié)果表明缩赛,新生代大小27M,使用了5.8M撰糠,其中Eden區(qū)24M酥馍,F(xiàn)rom Survivor,To Survivor各3M窗慎;老年代有60M物喷,使用了10M。
那么接下來遮斥,讓我們運行如下程序(方法2)
運行結(jié)果如下峦失,我們可以看到,由于第三次再分配9M空間的時候术吗,超過了Eden區(qū)的范圍尉辑,進行了一次垃圾回收,直接將18M分配到了老年代上较屿。
前面已經(jīng)介紹過隧魄,長期存活的對象進入老年代,晉升老年代的閾值可以通過-XX:MaxTenuringThreshold來設(shè)置隘蝎。
這里我們先設(shè)置為1购啄,運行如下代碼(方法3),
運行結(jié)果如下嘱么,進行了垃圾回收狮含,m2和m2_1加起來共有15M被分配到了老年代上。
另外還有幾條規(guī)則:
1. 如果在Survivor空間中相同年齡所有對象大小的總和大于Survivor空間的一半曼振,年齡大于等于該年齡的對象就可以直接進入年老代几迄。
2.
在發(fā)生Minor GC之前,虛擬機會先檢查老年代最大可用的連續(xù)空間是否大于新生代所有對象總空間冰评,如果這個條件成立映胁,那么Minor
GC可以確保是安全的。如果不成立甲雅,則虛擬機會查看HandlePromotionFailure設(shè)置值是否允許擔(dān)保失敗解孙。如果允許,那么會繼續(xù)檢查老年代最大可用的連續(xù)空間是否大于歷次晉升到老年代對象的平均大小务荆,如果大于妆距,將嘗試著進行一次Minor
GC,盡管這次Minor
GC是有風(fēng)險的函匕;如果小于娱据,或者HandlePromotionFailure設(shè)置不允許冒險,那這時也要改為進行一次Full GC。
這里就不一一展示了中剩,感興趣的朋友可以自己親手試一下忌穿。
有兩次名詞,這里也直接介紹一下结啼,Minor GC——新生代GC掠剑,指發(fā)生在新生代的垃圾收集動作。
Major GC/Full GC——老年代GC郊愧,指發(fā)生在老年代的垃圾收集動作朴译。
喜歡文章或想一起學(xué)習(xí)的朋友可以關(guān)注我,給我點贊属铁,我將會持續(xù)更新眠寿,有什么疑問或文中有不當之處請給我留言,真誠地希望能與大家一起交流探討焦蘑,學(xué)習(xí)進步盯拱。