[英]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 ║
╚════════════╩═══════════════════════╩════════════════╩═══════════════════╝
o1
, o2
和o3
是分配的實際對象。 可以在每個點輕松計算可以回收多少個物體; 在這種情況下,行后6 o1
是從一個根訪問, o3
是從訪問o1
和o2
訪問從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
args = null
t = 1000x
t2 = null
盡管Go_Stack在執行完成后將從內存中刪除。 為了完整,我把它保存在這里。
t = 1000x
t1 = 3000x
t2 = 5000x
通過查看Main_Stack和HEAP,可以觀察到我們可以直接或間接地訪問所有對象。
因此,當代碼執行到副主方法中的第7行時,沒有對象符合垃圾收集條件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.