一、引用計數算法:
判斷對象的引用數量:
通過判斷對象的引用數量來決定對象是否可以被回收;
每個對象實例都有一個引用計數器,被引用則+1,完成引用則-1;
任何引用計數為0的對象實例可以被當作垃圾收集;
優缺點:
優點:執行效率高,程序執行受影響較小;
缺點:無法檢測出循環引用的情況,導致內存泄漏;
二、可達性分析算法:
通過判斷對象的引用鏈是否可達來決定對象是否可以被回收;
jvm要做垃圾回收時,首先要判斷一個對象是否還有可能被使用。那么如何判斷一個對象是否還有可能被用到?
如果我們的程序無法再引用到該對象,那么這個對象就肯定可以被回收,這個狀態稱為不可達。當對象不可達,該對象就可以作為回收對象被垃圾回收器回收。
那么這個可達還是不可達如何判斷呢?
答案就是GC roots ,也就是根對象,如果從一個對象沒有到達根對象的路徑,或者說從根對象開始無法引用到該對象,該對象就是不可達的。
以下三類對象在jvm中作為GC roots,來判斷一個對象是否可以被回收
(通常來說我們只要知道虛擬機棧和靜態引用就夠了)
-
虛擬機棧(JVM stack)中引用的對象(准確的說是虛擬機棧中的棧幀(frames))
我們知道,每個方法執行的時候,jvm都會創建一個相應的棧幀(棧幀中包括操作數棧、局部變量表、運行時常量池的引用),棧幀中包含這在方法內部使用的所有對象的引用(當然還有其他的基本類型數據),當方法執行完后,該棧幀會從虛擬機棧中彈出,這樣一來,臨時創建的對象的引用也就不存在了,或者說沒有任何gc roots指向這些臨時對象,這些對象在下一次GC時便會被回收掉 -
方法區中類靜態屬性引用的對象
靜態屬性是該類型(class)的屬性,不單獨屬於任何實例,因此該屬性自然會作為gc roots。只要這個class存在,該引用指向的對象也會一直存在。class 也是會被回收的,在面后說明 -
本地方法棧(Native Stack)引用的對象
一個class要被回收准確的說應該是卸載,必須同時滿足以下三個條件
- 堆中不存在該類的任何實例
- 加載該類的classloader已經被回收
- 該類的java.lang.Class對象沒有在任何地方被引用,也就是說無法通過反射再帶訪問該類的信息