前面的文章介紹了對象的建立過程,其中第三步 —— 分配內存,只是簡單的介紹了分配的方式 —— 指針碰撞、空閒列表,其實內存在堆上分配還大有文章嘞。html
對象的內存分配,往大方向上講,就是在堆上分配,對象主要分配在新生代的 Eden 區上,若是啓動了本地線程分配緩衝,將按線程優先在 TLAB 上分配。少數狀況下也可能直接分配在老年代中,分配的規則並非百分之百固定的。其細節取決於當前使用的是哪種垃圾收集器的組合,還有虛擬機中與內存相關的參數的設置。數組
下面介紹一些常見的內存分配策略。性能
虛擬機將新生代內存分爲一塊較大的 Eden 空間和兩塊較小的 Survivor 空間(默認比例是 8:1:1),大多數狀況下,分配對象時,使用 Eden 和其中一塊 Survivor 空間,當沒有足夠空間進行分配時,虛擬機將會進行一次 MinorGC。ui
若是虛擬機打開了 TLAB,那麼對象優先在 TLAB 上分配。TLAB 全稱是本地線程分配緩衝(Thread Local Allocation Buffer),它是每一個線程在 Java 堆中預先分配的一小塊內存。由於 TLAB是線程私有的,沒有鎖開銷,所以性能較好,在 JDK7 以後默認開啓。線程
虛擬機提供了一個 -XX:PretenureSizeThreshold 參數,令大於這個設置值的對象直接在老年代分配,這樣作的目的是避免在 Eden 區和及兩個 Survivor 區之間發生大量的內存複製。注意!該參數只對 Serial 和 ParNew 收集器有效,Parallel Scavenge 並不認識該參數。指針
通常咱們代碼中常見的大對象是指那種很長的字符串以及數組,寫程序的時候應當避免,常常出現大對象容易致使內存還有很多空間時就提早觸發垃圾收集以獲取足夠的內存空間來「安置」它們。htm
還記得前面文章咱們介紹對象建立的時候,說到對象頭中有一個 「GC 分代年齡」 嗎?那麼這個是作啥用的呢?對象
若是對象在 Eden 出生並通過第一次 Minor GC 後仍然存活,而且能被 Survivor 容納的話,將被移動到 Survivor 空間中,而且對象年齡設爲1。對象在 Survivor 空間中每「熬過」一次 Minor GC,年齡就增長 1 歲,當它的年齡到達必定程度(最大爲 15 歲),就將會被晉升到老年代。對象晉升老年代的年齡閾值,能夠經過參數 -XX:MaxTenuringThreshold 設置。blog
對象是否可以晉升到老年代,也不全由 -XX:MaxTenuringThreshold 參數控制,若是 Survivor 空間中相同年齡的全部對象大小總和大於 Survivor 空間的一半,年齡大於或等於該年齡的對象就能夠直接進入老年代。內存
新生代在發生 Minor GC 以前,虛擬機會先檢查老年代最大可用的連續空間是否大於新生代全部對象之和(或者歷次晉升老年代對象的平均大小)。若是這個條件不成立,那麼虛擬機將直接進行 Full GC 動做;若是這個條件成立,那麼虛擬機就會進行一次 Minor GC 操做,可是此次 Minor GC 是有風險的,由於比較的值是平均值,可能出現極端的狀況 —— 大量對象在 Minor GC 後還存活,這時就只好在失敗後從新發起一次 Full GC。