時隔這麼久,這個系列又和大家見面了,感謝支持我的朋友,只要能給大家帶來一點點收穫,我真的時發自內心的開心!
今天先簡單瞭解一下虛擬機的垃圾收集器。
前面已經介紹過了,程序計數器,虛擬機棧和本地方法棧是屬於線程私有區域,這三個區域分配和回收都是確定的,方法和線程結束後,內存自認而然就回收了。
而Java堆和方法作爲公共區域回收則比較複雜,垃圾收集器所關注也是這兩個部分的內存。
但是如何判斷哪些對象應該被回收呢?
比較簡單的是引用計數算法:給對象增加一個計數器,多一個地方引用此對象,該對象的計數器就加1;少一個對此對象的引用,計數器就減1。
這種方式的優點是判斷效率高,但是也有一個嚴重的缺點:存在對象之間循環引用的問題。
比如在一段程序中,有如下引用方式,objA.instacce=objB和objB.instacce=objA,這種將不會被回收。
所以主流的Java虛擬機裏面並沒有使用這種方式,而是採用了另外一種方式——可達性分析算法。
基本思想:通過一系列的稱爲“GC Roots”的對象作爲起始點,從這些節點開始向下搜索,搜索所 走過的路徑稱爲引用鏈(Reference Chain),當一個對象到GC Roots沒有任何引用鏈相連 (用圖論的話來說,就是從GC Roots到這個對象不可達)時,則證明此對象是不可用的。(摘自《深入理解JAVA虛擬機》)
如下圖所示,object5,object6, object7沒有道GC Root對象的引用鏈,是可以被回收的。注意,這裏是可以被回收,這時並不一定會被立刻回收。
那麼,什麼樣的對象可以被選作爲GC Roots對象呢,主要有以下四類。
既然提到了”引用”,那麼JAVA中引用是怎麼定義的呢?
傳統的定義(1.2之前):如果reference類型的數據中存儲的數值代表的是另外一塊內存的起始地址。
但是在1.2之後,JAVA對引用進行了擴充,又分出以下四種(這裏不知道大家有沒有和我一開始一樣的困惑,這個引用類型不是說程序執行之後動態產生的引用狀態,而是在我們開發的時候,自己手動設置的引用類型)。
1 強引用:類似Object o = new Object()這類的引用,只要引用還在,即使出現OutOfMemoryError也不會被回收。
2 軟引用:使用WeakReference類來創建,代碼如下,當a=null的時候,垃圾收集器將會把a列入回收範圍,在內存不足時進行回收。屬於有用但非必需的對象。
A a = new A();
SoftReference b = new SoftReference (a);
3 弱引用:使用WeakReference類來創建,代碼如下,當a=null的時候,垃圾收集器將會把a列入回收範圍,垃圾收集的時候會被立刻回收。屬於非必需的對象。
4 虛引用:使用PhantomReference類來創建,不會對垃圾回收構成任何影響,用處是可以在被回收時接到一個系統通知。。
對象死亡會經歷兩次標記的過程,流程如下圖所示。
回收方法區
1 在新生代中,回收率效率,很高可以達到70%到95%的空間
2 在永久代中,主要回收廢棄常量和無用的類
“無用的類”的判定條件:
1. 該類所有的實例已經被回收
2. 加載該類的ClassLoder已經被回收
3. 該類對應的java.lang.Class對象沒有任何對方被引用