1.內存回收
java的運行時數(shù)據(jù)區(qū)分為方法區(qū)拆内、堆、虛擬機棧宠默、本地方法棧和程序計數(shù)器麸恍,內存回收關注的區(qū)域是java堆和方法區(qū),回收的對象是已經"死去"的對象。
2.判斷對象的死亡
引用計數(shù)法
給對象添加一個引用計數(shù)器抹沪,有地方引用他刻肄,計數(shù)器加一,引用失效融欧,計數(shù)器減一敏弃。計數(shù)器為0的對象判斷為死亡的對象。但是java中沒有采用引用計數(shù)法管理內存噪馏,理由是它很難解決對象循環(huán)引用的問題
可達性分析算法
java麦到、C#等語言采用可達性分析算法來判斷對象是否存活。具體做法是欠肾,通過一系列稱為"GC Roots"對象作為起始點瓶颠,從這些節(jié)點開始向下搜索,搜索所走過的路徑稱為引用鏈刺桃,當一個對象到"GC Roots"沒有引用鏈相連粹淋,就證明這個對象是不可達的。
java 引用
java希望描述這樣一類對象:當內存空間還足夠的時候瑟慈,能保留在內存中桃移;如果內存空間在進行垃圾回收后還是非常緊張,則可以拋棄這些對象葛碧。(例如WeakHashMap中的entry)
JDK1.2后對引用進行了擴充借杰,分為
- 強引用
類似Object obj = new Object
,只要強引用還存在进泼,垃圾收集器永遠不會回收掉被引用的對象第步。 - 軟引用
軟引用關聯(lián)著的對象,在系統(tǒng)即將拋出內存溢出異常之前缘琅,會將這些對象進行第二次回收粘都,如果這次回收后還沒有足夠的內存才會拋出內存溢出異常。(SoftReference類) - 弱引用
強度比軟引用更弱刷袍,被弱引用關聯(lián)的對象翩隧,只能生存到下一次垃圾收集發(fā)生之前。當垃圾收集器工作的時候呻纹,無論當前內存是否足夠堆生,都會回收掉只被弱引用關聯(lián)的對象。(WeakReference類) - 虛引用
最弱的引用關系雷酪,無法通過虛引用來取得一個對象實例淑仆。虛引用的唯一目的就是在這個對象被收集器回收的時候收到一個系統(tǒng)通知。
對象的finalize()方法
使用可達性分析算法中的不可達對象不會立刻被回收哥力,分兩步:
- 若對象分析不可達蔗怠,則對他進行第一次標記并進行篩選墩弯,篩選的根據(jù)對象是否需要執(zhí)行finalize()方法。finalize()方法只會被執(zhí)行一次(如果能重復執(zhí)行那么這個對象可能永遠無法回收)寞射。如果沒有必要執(zhí)行finalize方法渔工,會直接回收。
- 如果需要執(zhí)行finalize方法桥温,那么會對這些對象進行第二次標記引矩,如果在finalize()方法中建立有效引用完成自救,那么會對他進行第二次標記并將它移出即將回收的集合侵浸。
方法區(qū)的回收
方法區(qū)垃圾收集的效率遠低于堆旺韭,主要回收兩部分內容:
- 廢棄常量
和java堆中對象回收類似,主要包括常量池中的類(接口)掏觉、方法区端、字段的符號引用。 - 無用的類
判斷類是無用的類條件比較苛刻履腋,需要滿足下面三個條件:
a. 該類所有實例被回收
b.加載該類的ClassLoader已經被回收
c.該類對應的java.lang.Class沒有在任何地方引用
3.垃圾收集算法
標記-清除算法
標記出需要回收的對象珊燎,標記完成后統(tǒng)一回收所有被標記的對象执泰。CMS垃圾收集器就是采用這種算法炼杖。
優(yōu)勢:
最基礎算法仗哨。
劣勢:
標記、清除兩個過程效率都不高延旧;會產生空間碎片。
復制算法
解決了標記-清除算法中的空間碎片問題槽地。因為新生代中對象存活對象一般很少迁沫,可將內存分為一份較大的Eden區(qū)域,兩份較小的Survivor區(qū)域捌蚊,每次使用一個Eden和survivor區(qū)域集畅,進行垃圾回收的時候將這兩個區(qū)域的存活對象復制到另一個未使用的survivor區(qū)域上。如果survivor區(qū)域空間不夠缅糟,就會使用老年代進行分配擔保挺智。
優(yōu)勢:
適合對象存活率低的新生代,沒有空間碎片窗宦。
劣勢:
如果對象存活率高赦颇,那么復制操作的開銷會很大;會造成部分內存空間浪費赴涵。
標記-整理算法
適用于老年代的算法媒怯,就是在標記-清除算法的基礎上進行了空間整理,解決了空間碎片問題髓窜。
優(yōu)勢:
解決了空間碎片問題
劣勢:
移動對象也需要開銷
分代收集算法
當前商用虛擬機都采用分代收集算法扇苞,將內存分為兩個年代:
- 新生代
對象存活率較低的區(qū)域,適合復制算法 - 老年代
是新生代的分配擔保,對象存活率較高的區(qū)域杨拐,適合標記-整理祈餐、標記-清除算法。
4.Stop The world 問題
問題描述
在進行可達性分析的過程中哄陶,可能會出現(xiàn)引用關系不斷變化的情況帆阳,為了避免這個情況,需要停頓所有的進程再進行GC屋吨。
HotSpot算法實現(xiàn)
在GC Roots枚舉的時候蜒谤,使用OopMap數(shù)據(jù)結構來得知哪些地方存在引用,用來快速準確地完成根節(jié)點枚舉至扰。
為了避免OopMap空間開銷過大鳍徽,設立安全點,只有線程運行到安全點才會發(fā)生GC敢课。
安全點又帶來了新的問題阶祭,如果線程停止就無法運行到安全點。設立安全區(qū)域直秆,線程在安全區(qū)域的時候濒募,GC可以不用管這個線程。線程在出安全區(qū)域的時候圾结,要等這次GC完成瑰剃。
垃圾收集器
主要的新生代和老年代收集器如圖
CMS收集器
特點是并發(fā)收集,低停頓筝野,是非常優(yōu)秀的老年代收集器晌姚,使用標記-清除算法。由于停頓時間短歇竟,常用于互聯(lián)網服務器上挥唠。收集過程如下:
總結
為什么要進行內存回收?回收發(fā)生在哪里?回收哪些對象?回收算法?實際應用?