程序計數(shù)器吸占、虛擬機棧诫钓、本地方法棧3個區(qū)域隨線程而生,隨線程而滅菌湃,內(nèi)存分配和內(nèi)存回收都具備確定性,所以不需要過多考慮這幾個區(qū)域的回收問題骤坐。這里我們主要探究Java堆的回收機制下愈。
如何判斷對象可被回收
引用計數(shù)機制
給對象添加一個引用計數(shù)器纽绍,每當有一個地方引用它時势似,計數(shù)器值就加1;當引用失效時障簿,計數(shù)器值就減1栅迄。
該算法實現(xiàn)簡單,判定效率高毅舆,但因為無法解決對象之間相互循環(huán)引用的問題,現(xiàn)今主流的Java虛擬機并沒有選用它來管理內(nèi)存岂津。可達性分析算法
通過一系列的稱為“GC Roots”的對象作為起始點悦即,從這些點開始向下搜索,搜索所走過的路徑稱為引用鏈盐欺,當一個對象到GC Roots沒有任何引用鏈相連時,則證明此對象時不可用的魔种。
Java對象中粉洼,可作為GC Roots的對象:
1. 虛擬機棧中引用的對象叶摄。
2. 方法區(qū)中類靜態(tài)屬性引用的對象安拟。
3. 方法區(qū)中常量引用的對象。
4. 本地方法棧中JNI引用的對象糠赦。
一定會被回收嗎?
在可達性分析算法中淌山,即使被判斷為不可達的對象顾瞻,也不一定會被回收泼疑。如果一個對象實現(xiàn)了finalize()方法荷荤,并且該方法還沒有被虛擬機調(diào)用過,則在回收之前會調(diào)用此方法会油,若在此方法中袱蚓,將該對象與任何一個引用鏈上的對象關(guān)聯(lián)几蜻,則在finalize()調(diào)用后可以成功的變成可達的對象,從而避免被回收梭稚。方法區(qū)的回收
雖然說方法區(qū)回收的比率非常低,但也不是不能回收忱屑。
在常量池中暇昂,如果某個常量不被任何地方引用,則可以被清理出常量池急波。
判斷一個類是否是“無用的類”的條件苛刻許多,需要同時滿足以下三個條件:
1. 該類所有的實例都已經(jīng)被回收名段。
2. 加載該類的ClassLoader已經(jīng)被回收。
3. 該類對應的java.lang.Class對象沒有在任何地方被引用伸辟,無法在任何地方通過反射訪問該類的方法。
一般情況下我們不需要太關(guān)心方法區(qū)的回收問題窃蹋,但如果項目中大量使用到反射静稻、動態(tài)代理等頻繁自定義ClassLoader的場景則需要虛擬機具備類卸載的功能,以保證不會內(nèi)存溢出。
垃圾收集算法
標記 - 清除算法(Mark-Sweep)
最基礎(chǔ)的收集算法膝捞。首先標出所有需要回收的對象,在標記完成后統(tǒng)一回收所有被標記的對象晃酒。
該算法有兩個不足之處:一個是效率問題,標記和清除兩個過程的效率都不高;另一個是標記清除之后會產(chǎn)生大量不連續(xù)的內(nèi)存碎片摧茴,當遇到需要分配較大內(nèi)存的對象時,會因為無法找到足夠的連續(xù)內(nèi)存而提前觸發(fā)一次GC娃豹。復制算法(Copying)
該算法將可用的內(nèi)存安容量劃分為大小相等的兩塊购裙,每次只使用其中的一塊,當這一塊的內(nèi)存用完了躏率,就將還存活的對象復制到另一塊上面,然后再把以使用過的內(nèi)存空間一次性清理掉蓬抄。
該算法的代價是將可用內(nèi)存縮小為了原來的一半夯到。
但是實際情況中我們并不會真正按照1:1來劃分內(nèi)存空間,有研究表明新生代中98%的對象都是“朝生夕死”的黄娘,所以實際情況中將內(nèi)存空間分為一塊較大的Eden空間和兩塊較小的Survivor空間克滴,每次使用Eden和其中一塊Survivor优床,當回收時將Eden和Survivor中還存活的對象復制到另一塊上,然后清除掉Eden和剛才用過的Survivor空間着帽。HotSpot虛擬機默認Eden和Survivor的比例是8:1移层。這樣只需要付出10%的內(nèi)存,就能在絕大部分情況下順利完成回收工作观话,當Survivor空間不夠用時,則需要依賴其他內(nèi)存進行分配擔保灵迫。標記 - 整理算法(Mark - Compact)
復制算法不適用于回收率低的情況晦溪,所以老年代采用了“標記 - 整理”算法,標記過程依然與“標記 - 清除”算法一樣三圆,而后續(xù)步驟則是讓所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內(nèi)存修噪。分代收集算法(Generational Collection)
該算法根據(jù)對象存活周期的不同將內(nèi)存劃分為幾塊度气,一般是把Java堆氛圍新生代和老年代膨报,新生代的回收率非常高,則選用復制算法现柠;老年代的對象存活率高、沒有額外的空間對它進行分配擔保比然,就必須使用“標記 - 清理”或者“標記 - 整理”算法來進行回收周循。