在上一篇我們說過,自動記憶體管理分為兩部分:給物件分配記憶體和回收分配給物件的記憶體。這篇我們說說後者,也就是回收分配給物件的記憶體。回收記憶體要用到垃圾收集機制,英文名兒是GC(Garbage Collection)。
在本部分我們要解決以下幾個問題:
1、哪些記憶體需要回收?
2、什麼時候回收?
3、如何回收?
哪些記憶體需要回收?
堆和方法區的記憶體需要回收,其餘的不需要回收。
因為只有堆和方法區是執行緒共享的,其餘的是與執行緒「同生共死」的,執行緒結束,記憶體自然就跟著回收了,所以不用管它們。
什麼時候回收?
(1)在堆裡面:
當物件「死了」的時候就要對其進行記憶體回收了。啥叫對象死了?就是沒有地方引用它了,它無用了。那要怎麼判斷它是否死了呢?
有兩種方法:
引用計數演算法
為物件新增一個引用計數器,每當有一個地方引用它時,計數器的值就1,當引用失效時,計數器的值就-1,當計數器的值為0時,代表此物件已不被引用,也就是「可以死了」。
但這有一個弊端,就是循環引用的問題。就像下圖,堆裡的兩個物件即使無用了也沒辦法對其進行回收,因為它們互相引用著,計數器的值至少為1。
可達性分析
所有產生的物件都是稱為「GC Roots」的根的子樹。從GC Roots開始向下搜索,搜索所經過的路徑稱為引用鏈。當一個物件到GC Roots沒有任何引用鏈可以到達時,就稱這個物件是不可達的,也就是可以被GC回收了。這個是Java中採用較多的方式。
就像下圖中的堆中未被引用的對象,就可以對其進行回收。
怎麼判斷一個物件是否還存在著引用? java中的引用分為4種:
強引用:Object o=new Object(),只要強引用存在,GC就永遠不會回收被引用的物件。
軟引用:描述一些還有用但非必要的物件。當系統即將發生記憶體溢出了,就會回收。
弱引用:只要進行GC,就會對其進行回收。
虛引用:這是最弱的一種引用關係,無法透過虛引用來取得一個物件實例。它的作用是:能在這個物件被收集器回收時收到一個系統通知。
(2)在方法區裡面:
#我們知道,方法區裡儲存的是已被虛擬機器載入的類別訊息,常數,靜態變數,即時編譯器編譯後的程式碼等資料。所以我們在方法區裡面進行垃圾回收,回收的是一些廢棄的常數和無用的類別。
怎麼判斷一個常數是否被廢棄了?
看引用計數就可以,如果沒有物件來引用該常數,則表示此常數被廢棄了,也就可以回收了。
怎麼判斷一個類別是無用的類別?
有3種情況:
a、該類別所有的實例都已經被回收。
b、載入該類別的ClassLoader已經被回收。
c、該類別對應的java.lang.Class物件沒有任何地方被引用,無法在任何地方透過反射存取該類別的方法。
如何回收?
有4種演算法作為理論:
• 標記-清除演算法
• 複製演算法
• 標記-整理演算法
• 分代收集演算法
有5種收集器作為實作:
#後記
#記憶體溢位:系統無法再分配出你需要的空間。例如在堆中無法再給新生的物件分配記憶體了,在棧裡棧滿了無法再讓新棧幀進棧了。
記憶體洩漏:記憶體被物件佔用不還,就叫記憶體外洩。
以上便是關於JVM中垃圾回收機制的詳細講解,更多相關問題請訪問PHP中文網:JAVA影片教學
#以上是JAVA虛擬機器(JVM)詳細介紹(三)-垃圾收集機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!