2012-07-19 91 views
6

此問題取自Kathy SierraSCJP 1.6。有多少個對象符合垃圾回收的條件?有資格垃圾回收的對象

根據Kathy Sierra的回答,它是C。這意味着兩個對象有資格進行垃圾回收。我已經給出了答案的解釋。 但爲什麼c3不符合garbage collection(GC)的資格?

class CardBoard { 
    Short story = 200; 
    CardBoard go(CardBoard cb) { 
    cb = null; 
    return cb; 
} 

public static void main(String[] args) { 
    CardBoard c1 = new CardBoard(); 
    CardBoard c2 = new CardBoard(); 
    CardBoard c3 = c1.go(c2); 
    c1 = null; 
    // Do stuff 
} } 

當達到// Do stuff,有多少個對象資格GC?

  • A:0
  • B:1
  • C:2
  • d:編譯失敗
  • E:這是不可能知道
  • F:一個例外是在運行時引發

答:

  • C是正確的。只有一個CardBoard對象(c1)符合條件,但它具有相關聯的Short包裝器對象,該對象也符合條件。
  • 基於上述內容,A,B,D,E和F不正確。 (目標7.4)
+0

嚴格來說'c3'不能符合GC的條件,因爲*它不是一個對象*。它是一個變量可以指向一個對象。 – 2012-07-19 15:35:48

+0

正確的答案是[所有人](http://stackoverflow.com/a/26645534/2711488)... – Holger 2016-05-02 09:10:49

回答

6

c3指向的任何對象都不存在。構造函數只被調用兩次,兩個對象,分別由c1c2指向。 c3只是一個引用,它從來沒有被分配過任何東西,只是空指針。

當前指向null的參考c3不會超出範圍並從堆棧中移除,直到主方法結束處的右大括號超出範圍。因爲c1基準設置爲空,但c2參考尚未改變,因此分配給它的對象仍然是經由c2參考這個範圍可達

原來分配給c1對象是不可達。

+0

這是一個有趣的事情,有這麼多的教程和練習討論這樣的事情,他們都是錯誤的。事實是,JVM根本不知道局部變量的範圍。過去,這通常意味着有些參考文獻雖然超出範圍,但並未被清除。今天,您可能會對以下事實感到驚訝:即使在「範圍內」仍收集對象,請參閱[「在Java 8中調用強制可達對象的finalize()」](http://stackoverflow.com/q/26642153/2711488 )... – Holger 2016-05-02 09:15:04

+0

1)這個問題是關於java 6的2)不知道'// do stuff'可能包含什麼,不可能推測編譯器可能會對c2的未來可達性做出哪些優化結論。 – Affe 2016-05-03 16:46:54

+0

Java 6和Java 8之間的規則沒有改變。你甚至不能排除在實際的Java 6實現中會發生這樣的事情,只是它迄今尚未在SO上進行討論。如果你認爲'//做東西'可能包含與可達性有關的行爲,那麼正確的答案是這個問題是不完整的。這只是證明更多,這樣的問題是多麼毫無意義...... – Holger 2016-05-03 17:43:42

4

c3null,所以很明顯,沒有對象有資格進行垃圾回收。

注意,創建只有兩個CardBoard對象,這兩個在這些線路上:

CardBoard c1 = new CardBoard(); 
CardBoard c2 = new CardBoard(); 

和參考雜耍後,只有其中之一是沒有引用。

-1

如果您發現代碼中只創建了兩個對象。 c3從不初始化爲一個對象,它是一個空引用。因此,只有一個「對象」有資格進行垃圾回收。

7

讓我們通過線打破這行:

CardBoard c1 = new CardBoard(); 

我們現在有兩個對象,在CardBoardc1點和Shortc1.story。無論是供GC截至CardBoardc1點和CardBoard點在Shortstory變量...

CardBoard c2 = new CardBoard(); 

與上述類似,我們現在有四個對象,其中沒有一個是可供GC。

CardBoard c3 = c1.go(c2); 

我們調用的方法去紙板指向由c1,路過的c2的值,它是一個CardBoard對象的引用。我們將參數歸爲空,但是Java通過值意味着c2變量本身不受影響。然後我們返回空參數。 c3nullc1c2不受影響。我們仍然有4個對象,其中沒有一個可以用GC'd。

c1 = null; 

我們爲null c1。這c1以前在現在所指向的對象CardBoard沒有任何指向它,它可以GC'd。因爲CardBoard對象內部story變量在Short指向的唯一的事情,因爲這CardBoard對象符合GC的Short也變得適合GC。這給了我們4個物體,其中2個可以GC'd。資格GC的對象是以前由c1c1.story引用的那些。

1

的形式上正確的答案是,我們不知道。我們不知道原因是這一行:

Short story = 200; 

這將編譯到後面的字節代碼:

CardBoard(); 
Code: 
    0: aload_0 
    1: invokespecial #1     // Method java/lang/Object."<init>":()V 
    4: aload_0 
    5: sipush  200 
    8: invokestatic #2     // Method java/lang/Short.valueOf:(S)Ljava/lang/Short; 
    11: putfield  #3     // Field story:Ljava/lang/Short; 
    14: return 

8號線是這裏的關鍵,Short.valueOf(),它返回的盒裝相當於原始的200。讓我們來看看Short.valueOf()的Javadoc:在-128到127, 以下的範圍

此方法將總是緩存值,並可以緩存在這個範圍之外的其他值。

200不在「必須緩存」範圍內,因此屬於「可能緩存」範圍。如果緩存,當其含有CardBoard實例的story值將不符合GC。如果沒有緩存,story將無法​​訪問,因此GCed。

爲了使問題明確(和提議的答案是正確的),代碼應修正如下:

Short story = new Short(200); 

更新:1.6 JavadocShort.valueOf()是不是1.8版本我引用了更多神祕,但是也適用相同的邏輯:僅通過查看代碼是否將返回新的或緩存的實例Short就無法確定。