對于大多數(shù)應(yīng)用,Java 堆是 Java 虛擬機管理的內(nèi)存中最大的一塊,被所有線程共享。此內(nèi)存區(qū)域的唯一目的就是存放對象實例,幾乎所有的對象實例以及數(shù)據(jù)都在這里分配內(nèi)存。
為了進行高效的垃圾回收,虛擬機把堆內(nèi)存邏輯上劃分成三塊區(qū)域(分代的唯一理由就是優(yōu)化 GC 性能):
1、新生帶(年輕代):新對象和沒達到一定年齡的對象都在新生代
2、老年代(養(yǎng)老區(qū)):被長時間使用的對象,老年代的內(nèi)存空間應(yīng)該要比年輕代更大
Java 虛擬機規(guī)范規(guī)定,Java 堆可以是處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上是連續(xù)的即可,像磁盤空間一樣。實現(xiàn)時,既可以是固定大小,也可以是可擴展的,主流虛擬機都是可擴展的(通過 -Xmx 和 -Xms 控制),如果堆中沒有完成實例分配,并且堆無法再擴展時,就會拋出 OutOfMemoryError 異常。
年輕代 (Young Generation)
年輕代是所有新對象創(chuàng)建的地方。當(dāng)填充年輕代時,執(zhí)行垃圾收集。這種垃圾收集稱為 Minor GC。年輕一代被分為三個部分——伊甸園(Eden Memory)和兩個幸存區(qū)(Survivor Memory,被稱為from/to或s0/s1),默認(rèn)比例是8:1:1。
1、大多數(shù)新創(chuàng)建的對象都位于 Eden 內(nèi)存空間中;
2、當(dāng) Eden 空間被對象填充時,執(zhí)行Minor GC,并將所有幸存者對象移動到一個幸存者空間中;
3、Minor GC 檢查幸存者對象,并將它們移動到另一個幸存者空間。所以每次,一個幸存者空間總是空的;
4、經(jīng)過多次 GC 循環(huán)后存活下來的對象被移動到老年代。通常,這是通過設(shè)置年輕一代對象的年齡閾值來實現(xiàn)的,然后他們才有資格提升到老一代。
老年代(Old Generation)
舊的一代內(nèi)存包含那些經(jīng)過許多輪小型 GC 后仍然存活的對象。通常,垃圾收集是在老年代內(nèi)存滿時執(zhí)行的。老年代垃圾收集稱為 主GC(Major GC),通常需要更長的時間;
大對象直接進入老年代(大對象是指需要大量連續(xù)內(nèi)存空間的對象)。這樣做的目的是避免在 Eden 區(qū)和兩個Survivor 區(qū)之間發(fā)生大量的內(nèi)存拷貝。