哪些內(nèi)存需要回收
當(dāng)垃圾收集器對(duì)堆進(jìn)行回收前, 首先要確定當(dāng)前對(duì)象是否需要被回收, 所以第一步, 死亡判定
, 何為死亡呢, 就是說(shuō)當(dāng)前這個(gè)對(duì)象沒(méi)有被其他地方引用他, 他用不到了,沒(méi)作用了, 就判定死亡。
死亡判定的兩種算法,
引用計(jì)數(shù)器, 記錄該對(duì)象被引用的次數(shù), 實(shí)現(xiàn)簡(jiǎn)單, 缺點(diǎn)明顯, 無(wú)法解決循環(huán)引用的問(wèn)題。
可達(dá)性算法, 該算法也是主流JVM所使用的, 我們會(huì)生成一系列的GC Roots, 像這個(gè)樣子

判斷對(duì)象是否存活就是尋找引用鏈, 是否可達(dá)GC Roots,那么就要問(wèn)了, GC Roots是什么呢
GC Roots 也是堆中我們生成的對(duì)象, 只是這個(gè)對(duì)象有被下面幾個(gè)地方引用到, 那么就可作為GC Roots
- 虛擬機(jī)棧的棧幀中, 即方法中所引用的對(duì)象, 這點(diǎn)好理解吧, 我們?cè)谑褂靡粋€(gè)方法的時(shí)候, 可能會(huì)new幾個(gè)對(duì)象出來(lái), 那么這些對(duì)象都可以認(rèn)為是GC Roots, 這里的GC Roots 會(huì)隨著方法出棧而退出GC Root 集合, 就有被回收的機(jī)會(huì)了。
- 方法區(qū)中常量引用的對(duì)象, 方法區(qū),你又可以理解為永久代, 那么這里又是常量所引用的, 地址不會(huì)發(fā)生變化, 那么自然可以被當(dāng)做GC Roots了, 個(gè)人認(rèn)為這個(gè)GC Roots可以一直活著。
- 本地方法棧引用的對(duì)象, 和一同理
在jdk1.2,對(duì)引用的那根線, 也有了定義
對(duì)于引用呢, 我們有4種引用方式
- 強(qiáng)引用, new 的方式, 都是強(qiáng)引用, 垃圾收集器永遠(yuǎn)不會(huì)回收被引用的對(duì)象
- 軟引用 內(nèi)存即將發(fā)生溢出異常的時(shí)候, 會(huì)去先把這些引用回收掉, 看看還會(huì)不會(huì)溢出
- 弱引用, 垃圾收集器工作時(shí), 每次垃圾回收的時(shí)候,都會(huì)回收掉這個(gè)對(duì)象
- 虛引用, 弱的不行, 能干啥我也不知道
關(guān)于四個(gè)引用使用場(chǎng)景, 后來(lái)會(huì)再說(shuō)的。
那么除了對(duì)堆的回收, 方法區(qū)也是會(huì)有回收的, 主要針對(duì)廢棄常量和無(wú)用的類, 回收條件較苛刻, 還得調(diào)JVM參數(shù)
怎么回收這些對(duì)象
我們之前有點(diǎn)東西忘說(shuō)了, 就是在進(jìn)行可達(dá)性分析的時(shí)候, 會(huì)對(duì)要回收的對(duì)象進(jìn)行標(biāo)記, 標(biāo)記了的就要被回收, 針對(duì)回收方式, 由以下算法演進(jìn)
-
標(biāo)記-清除算法
將需要回收的對(duì)象標(biāo)記, 然后直接清除

別看圖是很規(guī)整的, 堆中分配的空間是由對(duì)象決定的, 所以呢, 這樣的標(biāo)記清除, 則會(huì)讓內(nèi)存碎片化嚴(yán)重, 這時(shí)候創(chuàng)建對(duì)象呢, 就是向這些回收的后的空隙內(nèi)存中選取合適大小的塊來(lái)分配, 如果這個(gè)對(duì)象需要很大的內(nèi)存塊,而又沒(méi)有找到, 那么就尷尬了, 對(duì)吧。
-
復(fù)制算法
將內(nèi)存分為兩塊, 每次回收, 將存活對(duì)象扔到另一邊, 清除用過(guò)的那塊
復(fù)制算法
就是兩塊內(nèi)存換著用, 來(lái)回倒, 另一塊直接清0, 當(dāng)然, 這樣做缺點(diǎn)也很明顯, 浪費(fèi)了一整半空間, 再講分代收集的時(shí)候, 我們會(huì)繼續(xù)談此算法。 標(biāo)記-整理
很類似于標(biāo)記清除, 只是直接移動(dòng)存貨對(duì)象到一塊, 然后整體清零邊界, 像這個(gè)樣子

- 分代收集
啊哈, 分代收集和我們之前的對(duì)象頭扯到一塊了, 我們知道對(duì)象頭里包含了對(duì)象的分代年齡, 對(duì)于不同的年齡呢, 我們把GC堆分為了新生代, 和老年代, 新生代回收都能回收走大量的對(duì)象, 老年代一般死亡的對(duì)象很少, 因此呢, 針對(duì)這樣的問(wèn)題, 新生代采用復(fù)制算法(優(yōu)化過(guò)的, 針對(duì)新生代需進(jìn)行大量回收),老年代采用標(biāo)記整理或標(biāo)記清楚。
優(yōu)化的復(fù)制算法長(zhǎng)啥樣呢, 我們先來(lái)描述一下, 將原本的一半一半, 變成了8-1-1, 我們清楚, 新生代伴隨大量?jī)?nèi)存回收, 存活下來(lái)的比較少, 每次使用8-1 塊, 然后, 回收的時(shí)候, 將存活的復(fù)制到另一塊小區(qū)域中, 并且清除8-1塊, 就不畫圖了。這里要注意, 有時(shí)候可能存活的不止1的比例, 超出1的呢, 會(huì)通過(guò)分配擔(dān)保機(jī)制, 提前進(jìn)入老年代。
