簡體   English   中英

什么時候字符串會在java中被垃圾收集

[英]When will a string be garbage collected in java

在 Java 中,當一個對象沒有活動引用時,它就有資格進行垃圾回收。 現在在字符串的情況下,情況並非如此,因為字符串將進入字符串池,JVM 將使對象保持活動狀態以供重用。 那么這意味着一旦創建的字符串將“永遠不會”被垃圾收集?

現在,對於字符串,情況並非如此,因為字符串將進入字符串池,而 JVM 將使對象保持活動狀態以供重用。 那么這意味着一旦創建的字符串將“永遠不會”被垃圾收集?

首先,只有字符串文字(見注釋)會自動插入/添加到字符串池中。 應用程序在運行時創建的String對象不會被實習......除非您的應用程序顯式調用String.intern()

其次,實際上字符串池中對象的垃圾回收規則與其他String對象的規則相同:實際上是所有對象。 如果 GC 發現它們不可達,它們將被垃圾回收。

實際上,對應於字符串文字的String對象通常不會成為垃圾回收的候選對象。 這是因為在使用字面量的每個方法的代碼中都有一個對String對象的隱式引用。 這意味着只要方法可以執行, String就可以訪問。

然而,情況並非總是如此。 如果在動態加載的類中定義了字符串文字(例如使用Class.forName(...) ),則可以安排該類被卸載 如果發生這種情況,則對應於文字的String對象可能無法訪問,並且最終可能會被 GC 處理。

另請參閱: Java 中的類垃圾收集何時以及如何進行?


筆記:

  1. 字符串文字 ( JLS 3.10.5 ) 是出現在 Java 源代碼中的字符串; 例如

     "abc" // string literal new String(...) // not a string literal
  2. 通過(編譯時)常量表達式 ( JLS 15.28 ) 的評估產生的字符串也可以被實習。

     "abc" + 123 // this is a constant expression
  3. 嚴格來說,並不是所有的 String 字面量都是實習的:

    • 如果字符串字面量僅作為常量表達式的子表達式出現在源代碼中,則該字面量可能不會以任何形式出現在“.class”文件 這樣的文字不會被實習,因為它在運行時不存在。

    • 在 Java 9+ 中,涉及非編譯時常量的文字和值的字符串連接可能會有不同的處理方式。 現在,在字節碼編譯器的選項中,字符串連接如下:

       int x = 42; // not a compile time constant String s = "prefix " + x + " suffix";

      可能會導致字符串常量如下所示:

       "prefix \\1 suffix"

      在運行時,上面的字符串常量被用作生成動態連接方法的“配方”。 原始字符串文字(即"prefix "" suffix" )不會變成內部字符串對象。

      感謝@Holger指出這一點。 更多細節在JEP 280StringConcatFactoryjavadoc中。

  4. 在 Java 7 之前,字符串池在 PermGen 中。 對於某些版本的 Java,如果您選擇了 CMS 收集器,則默認情況下不會啟用 PermGen 的垃圾收集。 但是 CMS 從來都不是默認的收集器,並且有一個標志可以讓 CMS 啟用 PermGen 收集。 (而且沒有人應該再為 Java 6 及更早版本開發代碼了。)

你是對的; 實習生池中的字符串永遠不會被 GC 處理。

但是,大多數字符串都沒有被實習。
字符串字面量是固定的,傳遞給String.intern()的字符串是固定的,但所有其他字符串都不會被固定並且可以正常進行 GC。

字符串池中的字符串對象不會被垃圾回收。 如果您在程序執行中沒有引用它,其他 String 對象將被垃圾收集。

您可能會問哪些字符串對象進入字符串池。字符串池中的對象是:

  • 編譯時文字(例如String s1 = "123";

  • 運行時中的String s2 = new String("test").intern();字符串對象(例如String s2 = new String("test").intern();

s1s2引用字符串池中的字符串對象。

任何在運行時創建且未駐留的對象都將充當普通對象並駐留在堆內存中。 這些對象可以被垃圾回收。

一個例子是: String s3 = s1 + s2;

在這里, s3引用了一個字符串對象,該對象與其他對象一起駐留在堆內存中(不在字符串池中)。

在 Java 7 之前,字符串池駐留在永久代空間中。 所以字符串字面量從來沒有被垃圾收集過(這也導致了很多次內存不足的問題)在 Java 7 之后,字符串池被放置在堆空間中,這是由 JVM 垃圾收集的。 它還減少了在 JVM 中出現內存不足問題的機會。

暫無
暫無

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

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