垃圾回收狀況:java
一、 對象沒有引用算法
二、 做用域發生未捕獲異常spa
三、 程序在做用域正常執行完畢orm
四、 程序執行了System.exit()對象
五、 程序發生意外終止(被殺進程等)進程
垃圾回收算法:圖片
1引用計數器算法內存
在JDK1.2以前,使用的是引用計數器算法,即當這個類被加載到內存之後,就會產生方法區,堆棧、程序計數器等一系列信息,當建立對象的時候,爲這個對象在堆棧空間中分配對象,同時會產生一個引用計數器,同時引用計數器+1,當有新的引用的時候,引用計數器繼續+1,而當其中一個引用銷燬的時候,引用計數器-1,當引用計數器被減爲零的時候,標誌着這個對象已經沒有引用了,能夠回收了!這種算法在JDK1.2以前的版本被普遍使用,作用域
可是隨着業務的發展,很快出現了一個問題虛擬機
當咱們的代碼出現下面的情形時,該算法將沒法適應
a) ObjA.obj = ObjB
b) ObjB.obj - ObjA
這樣的代碼會產生以下引用情形 objA指向objB,而objB又指向objA,這樣當其餘全部的引用都消失了以後,objA和objB還有一個相互的引用,也就是說兩個對象的引用計數器各爲1,而實際上這兩個對象都已經沒有額外的引用,已是垃圾了。
二、 根搜索算法
根搜索算法是從離散數學中的圖論引入的,程序把全部的引用關係看做一張圖,從一個節點GC ROOT開始,尋找對應的引用節點,找到這個節點之後,繼續尋找這個節點的引用節點,當全部的引用節點尋找完畢以後,剩餘的節點則被認爲是沒有被引用到的節點,即無用的節點。
目前java中可做爲GC Root的對象有
一、 虛擬機棧中引用的對象(本地變量表)
二、 方法區中靜態屬性引用的對象
三、 方法區中常量引用的對象
四、 本地方法棧中引用的對象(Native對象)
瞭解了JVM是怎麼肯定對象是「垃圾」以後,進入正題,讓咱們來看看垃圾回收的算法。
標記—清除算法兩個階段:「標記」和「清除」。在標記階段,肯定全部要回收的對象,並作標記。清除階段緊隨標記階段,將標記階段肯定不可用的對象清除。
標記—清除算法是基礎的收集算法,標記和清除階段的效率不高,並且清除後回產生大量的不連續空間,這樣當程序須要分配大內存對象時,可能沒法找到足夠的連續空間。
垃圾回收前:
垃圾回收後:
綠色:存活對象 紅色:可回收對象 白色:未使用空間
複製算法是把內存分紅大小相等的兩塊,每次使用其中一塊,當垃圾回收的時候,把存活的對象複製到另外一塊上,而後把這塊內存整個清理掉。
複製算法實現簡單,運行效率高,可是因爲每次只能使用其中的一半,形成內存的利用率不高。如今的JVM用複製方法收集新生代,因爲新生代中大部分對象(98%)都是朝生夕死的,因此兩塊內存的比例不是1:1(大概是8:1)。
垃圾回收前:
垃圾回收後:
綠色:存活對象 紅色:可回收對象 白色:未使用空間
標記—整理算法和標記—清除算法同樣,可是標記—整理算法不是把存活對象複製到另外一塊內存,而是把存活對象往內存的一端移動,而後直接回收邊界之外的內存。
標記—整理算法提升了內存的利用率,而且它適合在收集對象存活時間較長的老年代。
垃圾回收前:
垃圾回收後:
綠色:存活對象 紅色:可回收對象 白色:未使用空間
分代收集是根據對象的存活時間把內存分爲新生代和舊生代,根據個代對象的存活特色,每一個代採用不一樣的垃圾回收算法。新生代採用標記—複製算法,old採用標記—整理算法。
垃圾算法的實現涉及大量的程序細節,並且不一樣的虛擬機平臺實現的方法也各不相同。上面介紹的只不過是基本思想。