2013-03-10 150 views
17

我在閱讀有關垃圾回收的問題,當我搜索字符串文字垃圾回收時,我感到困惑的搜索結果。字符串文字的垃圾回收

我需要澄清以下幾點:如果字符串被定義爲在編譯時文字

  1. [e.g:String str = "java"]那麼這將是垃圾回收?

  2. 如果使用實習方法[例如:String str = new String("java").intern()]那麼它會被垃圾收集?它也將被視爲與第1點中的字符串字面值不同。

  3. 有些地方提到,只有當String類將被卸載時,文字纔會被垃圾收集。這是否有意義,因爲我認爲String類將永遠不會被卸載。

+2

1 - http://stackoverflow.com/questions/2202162/garbage-collection-and-strings; 2 - http://stackoverflow.com/questions/6470651/creating-a-memory-leak-with-java; 3 - String a = new String(「asd」) - >「a」引用將被垃圾回收,但只是對「asd」的引用,並且「asd」將永遠存在。 – user1050755 2013-03-10 15:54:52

+0

如果你搜索更多,你會發現提到的地方使用實習生創建的字符串文字可以垃圾收集,因爲他們使用弱參考,但我不能確認它,這就是爲什麼我張貼的原因,因爲有很多混合的反應。 – Lokesh 2013-03-10 15:57:50

回答

18

如果在編譯時將字符串定義爲文字[例如:String str = "java";]那麼它會被垃圾收集?

可能不是。代碼對象將包含對錶示文字的String對象的一個​​或多個引用。所以只要代碼對象可達,String對象就會到達。

代碼對象可能無法訪問,但前提是它們是動態加載的......並且它們的類加載器被破壞。

如果我使用實習方法[e。g:String str = new String("java").intern()]那麼它會被垃圾收集?

intern調用返回的對象將是表示"java"字符串文字的相同對象。 (該"java"文字是在類加載時間實習。然後,當您實習生新構造String對象在您的代碼段,它會查找並返回先前實習"java"字符串)。

然而,實習是不相同的字符串字符串文字可以垃圾收集一旦變得無法訪問。 PermGen空間在所有最近的HotSpot JVM上收集的垃圾。 (現有到Java 8 ...而下降的PermGen完全。)

而且將它從字符串文本區別對待在點1

否...因爲它是相同的對象字符串文字。

事實上,一旦你明白髮生了什麼,很明顯字符串文字也沒有被特別處理。這只是「可達性」規則的應用...

有些地方提到文字將被垃圾收集只有當String類將被卸載?這是否有意義,因爲我認爲String類不會被卸載。

你說得對。這沒有意義。說這些來源是不正確的。 (如果您發佈了一個URL,以便我們可以閱讀他們正在說的內容,這將對您有所幫助...)

+1

對於#1,當你說代碼對象包含對字符串文字的引用時,你指的是什麼? – Mercenary 2013-11-12 14:00:59

+4

代碼對象(字節碼或本機編譯)中的某處會有指令需要獲取對應於字面值的String對象的引用。引用嵌入代碼本身,或者將其存儲在與代碼關聯的專用框架中。無論哪種方式,只要代碼*可以被執行,引用就是「可到達的」。 – 2013-11-13 05:10:29

+0

謝謝。而且,是JVM中方法區域的字符串實習池部分? – Mercenary 2013-11-13 10:30:44

9

在正常情況下,字符串文字和類都被分配到JVM的永久代(「PermGen」)中,並且通常不會被收集。被執行的字符串(例如mystring.intern())被存儲在permgen中的String類所擁有的內存池中,曾經有一種情況是,積極的interning可能會導致空間泄漏,因爲字符串池本身持有對每個字符串的引用,即使沒有其他參考存在。顯然這不再是真實的,至少從JDK 1.6開始(參見,例如,here)。

欲瞭解更多permgen,this是一個體面的主題概述。 (注意:該鏈接轉到與產品相關的博客,我與博客,公司或產品沒有任何關聯,但博客條目非常有用,並且與產品無關。 )

+2

這是不正確的。 PermGen空間>>是「垃圾收集。 – 2013-03-10 16:07:07

+0

你當然是對的。我的意圖只是說,在正常情況下,分配給permgen的數據不會得到GC,但我誤解了。稍微改寫一下。 – jacobm 2013-03-10 16:12:12

+0

事實上,深入挖掘,我發現被攔截的字符串不會被垃圾回收。 (這不是因爲permgen空間,這是由於'String#intern'的實現。)改變我的答案以反映這一點。 – jacobm 2013-03-10 16:38:47

0
  1. 只要程序在內存中,文字字符串就會保留在內存中。
  2. str將垃圾收集,但它創建的文字不會。
  3. 這非常合理,因爲卸載程序時會卸載字符串類。
+0

你可以給我一個例子,可以卸載字符串嗎?因爲我相信字符串文字也必須在Java類中使用,因爲字符串文字是常量,卸載可能需要根據我的知識卸載CLassLoader。你同意嗎? – Lokesh 2013-03-10 16:04:51

+0

根據我的知識,字符串文字不能以編程方式卸載。當程序終止時,它們將被卸載或銷燬。 – fredrik 2013-03-10 16:06:33

+1

@fredrik - 如果已經動態加載的類被卸載,它們也可以被垃圾回收。當JVM運行正常時,可能會發生這種情況。 – 2013-03-10 17:27:59

-3

intern()方法檢查字符串池中對象的可用性。如果對象/文字可用,則將返回其引用。如果文字不存在於池中,則將對象加載到perm區域(String pool)中,然後返回對其的引用。我們必須明智地使用intern()方法。

+0

根據定義,文字總是在游泳池中。 – EJP 2017-11-19 10:19:18