對象的內(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
*/
}