簡體   English   中英

有多少對象符合垃圾收集條件?

[英]How Many Objects Are Eligible For Garbage Collection?

1.  public class Tahiti {
2.      Tahiti t;
3.      public static void main(String[] args) {
4.          Tahiti t = new Tahiti();
5.          Tahiti t2 = t.go(t);
6.          t2 = null;
7.          // more code here
8.      }
9.      Tahiti go(Tahiti t) {
10.         Tahiti t1 = new Tahiti(); Tahiti t2 = new Tahiti();
11.         t1.t = t2; t2.t = t1; t.t = t2;
12.         return t1;
13.     }
14. }

到達第7行時,有多少對象符合垃圾回收的條件?

根據這個問題給出的答案,第11行沒有符合GC資格的對象; 但據我說,至少有一個對象,t2,在第6行設置為null,應該有資格進行垃圾收集。

第6行的變量t2不是對象的唯一引用。 從t到對象t2的引用是在函數go中創建的,而對象t2又保持對t1的引用,t1是函數go返回的相同對象。 因此,第6行僅減少了引用的數量,但仍然存在對該對象的實時引用。

編輯:讓我們嘗試更詳細的解釋,首先我重新編寫代碼,使解釋更容易。 每行一個語句和較少混淆的變量名稱+我用字母A,B和C標識了三個相關對象。

1.  public class Tahiti {
2.      Tahiti u;
3.      public static void main(String[] args) {
4.          Tahiti t = new Tahiti(); // object A
5.          Tahiti t2 = t.go(t);
6.          t2 = null;
7.          // more code here
8.      }
9.      Tahiti go(Tahiti s) {
10.         Tahiti s1 = new Tahiti(); // object B
11.         Tahiti s2 = new Tahiti(); // object C
12.         s1.u = s2;
13.         s2.u = s1;
14.         s.u = s2;
15.         return s1;
16.     }
17. }

在第4行:變量t被初始化以引用新對象。 讓我們稱這個對象本身為A(它通常在java中沒有名稱,但為了這個解釋,它會更容易)。

在第5行:t傳遞給函數go,所以我們轉到第9行

在第9行:參數s引用在第4行創建的對象A.

第10行:初始化變量s1以指向對象B.

第11行:初始化變量s2以引用對象C.

第12行:s1.u設置為引用s2,這意味着對象B獲得對C的引用

第13行:s2.u設置為引用s1,因此對象C得到對B的引用

第14行:su設置為引用s2,這意味着對象A獲得對C的引用,注意C也引用了B,所以此時有一個從A到B的鏈

第15行返回對象B並返回第5行

第5行:t2被設置為參考對象B(B現在直接被t2引用兩次,一次因為t指對象A,其指的是指C的C)

第6行:引用t2設置為null,因此B丟失一個引用但是t仍然是活的,指向A指的是C指的是B

您可以繪制一個表格,該表格在行之間進行映射,並且在行之后立即指向每個對象的訪問路徑列表,如下所示:

╔════════════╦═══════════════════════╦════════════════╦═══════════════════╗
║ After Line ║ Pointers to o1        ║ Pointers to o2 ║ Pointers to o3    ║
╠════════════╬═══════════════════════╬════════════════╬═══════════════════╣
║          3 ║ not allocated         ║ not allocated  ║ not allocated     ║
║          4 ║ main:t                ║ not allocated  ║ not allocated     ║
║          9 ║ main:t, go:this, go:t ║ not allocated  ║ not allocated     ║
║         10 ║ main:t, go:this, go:t ║ go:t1          ║ go:t2             ║
║         11 ║ main:t, go:this, go:t ║ go:t1, o3.t    ║ go:t2, o2.t, o1.t ║
║          5 ║ main:t                ║ main:t2, o3.t  ║ o2.t, o1.t        ║
║          6 ║ main:t                ║ o3.t           ║ o2.t, o1.t        ║
╚════════════╩═══════════════════════╩════════════════╩═══════════════════╝

o1o2o3是分配的實際對象。 可以在每個點輕松計算可以回收多少個物體; 在這種情況下,行后6 o1是從一個根訪問, o3是從訪問o1o2訪問從o3 ,所以沒有對象可以被回收。

作為旁注,我注意到你寫了“但根據我至少有一個對象, t2 ,......”。 如果這是你需要解決的問題,我建議放棄用指向它們的變量來命名對象的習慣; 而是為每個對象提供一個虛構的id,就像我上面用o<n>所做的那樣,並將變量視為指向這些對象的指針而不是它們的名稱。 這是因為,與指針和名稱不同,對象可能具有多於或少於一個與之關聯的變量,並且關聯變量列表可以一直改變。

在第5行,你調用方法Tahiti.go() ,所以程序從第5行跳到10,到6為6。

第11行在第6行之前執行

堆棧圖是確定哪些對象符合垃圾回收條件的最佳方法:

以下是上面代碼的堆棧圖:

1000x: TahitiObj: t:2000x

2000x: TahitiObj: 5000x

3000x: TahitiObj: t: 4000x

4000x: TahitiObj: 5000x

5000x: TahitiObj: t: 6000x

6000x: TahitiObj: 3000x

Main_Stack

args = null

t = 1000x

t2 = null

盡管Go_Stack在執行完成后將從內存中刪除。 為了完整,我把它保存在這里。

Go_Stack

t = 1000x

t1 = 3000x

t2 = 5000x

通過查看Main_Stack和HEAP,可以觀察到我們可以直接或間接地訪問所有對象。

因此,當代碼執行到副主方法中的第7行時,沒有對象符合垃圾收集條件。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM