目錄
垃圾的條件
1、引用計數法
2、可達性分析
3、強引用
4、軟引用
5、弱引用
6、虛引用
判斷垃圾的條件
在Java虛擬機(JVM)中,垃圾收集器負責管理內存,其中的垃圾收集算法用于確定哪些對象是垃圾,可以被回收以釋放內存空間。Java中主要使用的是自動內存管理,垃圾收集器會自動識別和回收不再被程序引用的對象。以下是一些判定對象為垃圾的條件:
1、引用計數法
引用計數法是一種簡單而直觀的垃圾收集算法,其核心思想是通過在對象頭中添加一個引用計數器,記錄該對象被引用的次數。每當有一個新的引用指向該對象時,引用計數加一;當引用被刪除或者超出作用范圍時,引用計數減一。當引用計數為零時,表示該對象不再被引用,即可以被回收。
然而,引用計數法有一個明顯的缺陷,即難以處理循環引用的情況。例如,兩個對象互相引用,它們的引用計數永遠不會變為零,即使它們已經不再被程序所使用。
以下是一個簡單的引用計數法的Java代碼示例:
class ReferenceCountingObject {private int referenceCount = 0;public ReferenceCountingObject() {// 對象初始化時,引用計數為 0}public void addReference() {referenceCount++;}public void removeReference() {referenceCount--;if (referenceCount == 0) {// 當引用計數為零時,可以進行垃圾回收操作System.out.println("對象被回收");}}
}public class ReferenceCountingExample {public static void main(String[] args) {// 創建兩個對象ReferenceCountingObject obj1 = new ReferenceCountingObject();ReferenceCountingObject obj2 = new ReferenceCountingObject();// obj1 引用計數加一obj1.addReference();// obj2 引用計數加一obj2.addReference();// obj1 引用計數減一obj1.removeReference();// obj1 引用計數為零,可以進行垃圾回收// obj2 引用計數仍為一}
}
2、可達性分析
可達性分析是Java虛擬機中垃圾收集的核心算法之一,它主要通過判斷對象是否能夠從一組稱為"GC Roots"的根對象出發,通過引用鏈追蹤,最終判斷對象是否可達。以下是關于可達性分析的一些詳細細節和Java代碼示例:
-
GC Roots: GC Roots包括虛擬機棧中引用的對象、方法區中類靜態屬性引用的對象、方法區中常量引用的對象以及本地方法棧中JNI(Java Native Interface)引用的對象。這些對象被認為是程序的根對象,是可達性分析的起始點。
-
可達性分析過程: 從GC Roots出發,通過對象引用鏈逐步追蹤,判斷對象是否能夠被程序訪問到。如果對象能夠通過一系列引用到達GC Roots,則該對象被認為是可達的;反之,如果無法到達,則被認為是不可達的。
-
標記-清除算法: 在可達性分析過程中,標記-清除算法是一種常用的垃圾收集算法。通過標記可達的對象,然后清除不可達的對象,最終回收被標記的垃圾。
下面是一個簡單的Java代碼示例,演示了可達性分析的基本原理:
class MyClass {// 成員變量,作為引用private MyClass reference;public MyClass() {this.reference = null;}public void setReference(MyClass anotherObject) {this.reference = anotherObject;}
}public class ReachabilityAnalysisExample {public static void main(String[] args) {// 創建對象1MyClass obj1 = new MyClass();// 創建對象2MyClass obj2 = new MyClass();// obj1 的 reference 成員變量指向 obj2obj1.setReference(obj2);// obj2 的 reference 成員變量為空,不指向其他對象// 現在,obj1 和 obj2 都是可達的,因為它們可以通過引用鏈相互訪問// 將 obj1 置為 null,切斷對 obj1 的引用obj1 = null;// 現在,obj1 不可達,因為沒有其他引用指向它,但 obj2 仍然可達// 執行垃圾回收System.gc();// 垃圾回收器可能會回收不可達的對象,釋放其占用的內存// 在實際應用中,Java 虛擬機會根據不同的垃圾收集算法和策略執行垃圾回收}
}
?
3、強引用
強引用是最常見的引用類型,只要強引用存在,垃圾收集器就不會回收被引用的對象。當沒有任何強引用指向一個對象時,該對象就變得不可達。
-
特點: 強引用是最常見的引用類型,它會使對象始終保持存活。只要存在強引用指向一個對象,垃圾收集器就不會回收該對象。
-
使用場景: 大多數對象的引用都是強引用,例如通過
new
操作符創建的對象就是強引用。當程序員希望確保對象不被垃圾收集器回收時,使用強引用是合適的。
Object obj = new Object(); // 強引用
?
4、軟引用
軟引用用于描述一些還有用但非必需的對象。在系統將要發生內存溢出之前,會嘗試回收軟引用指向的對象。
-
特點: 軟引用用于描述一些還有用但非必需的對象。當系統內存不足時,垃圾收集器會根據軟引用的情況來決定是否回收該對象,以釋放內存。
-
使用場景: 軟引用通常用于實現緩存策略,允許在內存不足時回收部分緩存而不會導致程序崩潰。
SoftReference<Object> softRef = new SoftReference<>(new Object());
Object obj = softRef.get(); // 獲取軟引用指向的對象
5、弱引用
弱引用也用于描述非必需對象,但它的生命周期比軟引用更短。當垃圾收集器運行時,無論內存是否足夠,都會回收被弱引用指向的對象。
-
特點: 弱引用描述的是非必需對象,其生命周期比軟引用更短。當垃圾收集器運行時,無論內存是否足夠,都會回收被弱引用指向的對象。
-
使用場景: 弱引用常用于實現對象緩存,但不希望緩存的對象影響垃圾回收。
WeakReference<Object> weakRef = new WeakReference<>(new Object());
Object obj = weakRef.get(); // 獲取弱引用指向的對象
6、虛引用
虛引用是最弱的引用類型,幾乎沒有保持對象存活的作用。主要用于對象被回收前的一些清理操作。
-
特點: 虛引用是最弱的引用類型,幾乎沒有保持對象存活的作用。主要用于對象被回收前的一些清理操作。虛引用必須和引用隊列(ReferenceQueue)一起使用。
-
使用場景: 虛引用主要用于跟蹤對象被垃圾收集的狀態,執行一些清理操作或者資源釋放。
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
PhantomReference<Object> phantomRef = new PhantomReference<>(new Object(), referenceQueue);
// 虛引用不提供 get 方法,因為其并不保持對象的存活,需要通過 ReferenceQueue 來獲取通知
Object obj = phantomRef.get(); // 返回始終為 null
?總體而言,這些引用類型在Java中提供了更靈活的內存管理手段,允許開發人員根據不同的場景來控制對象的生命周期。選擇合適的引用類型取決于應用程序的需求,以及對內存使用和性能的權衡。