2013-05-31 25 views
1

當我們實習一個字符串時,我們確保該字符串的所有用途都指向同一個實例。Interning字符串

我會假設底層字符串對象在堆中。

但是,存儲在存儲器中的引用變量在哪裏?

它是否具有與static相同的行爲 - 其中引用存儲在permgen中,並且只有在類加載器(和應用程序)退出後才使字符串實例可用於gc?

+1

靜態引用不會存儲在perm gen中。 – SimonC

+0

不確定你所說的「引用變量」是什麼意思。有一個interned字符串的目錄,但這是隱藏的,你不需要擔心它。任何需要使用interned字符串的引用都可以擁有您想要的任何存儲類。 –

+1

@SimonC - 實際上,靜態引用可以在permgen中,因爲持有它們的靜態框架可以是一個permgen對象。 (對於靜態框架在permgen中它肯定是有意義的,因爲它的生命週期與加載類的類加載器相關聯!)它只是靜態變量引用的對象,通常不是。 –

回答

5

直到JDK 6,Intern'ed字符串被存儲在內存池中的一個稱爲Permanent Generation的地方,這是爲非用戶對象保留的JVM區域,如類,方法和其他內部JVM對象。這個區域的大小是有限的,並且通常比堆小得多。

從JDK 7開始,interned字符串不再分配在Java堆的永久生成中,而是分配在Java堆的主要部分(稱爲年輕人和老一代)中,以及其他對象由應用程序創建。此更改將導致更多數據駐留在主Java堆中,永久生成中的數據更少,因此可能需要調整堆大小。由於這種變化,大多數應用程序在堆使用中只會看到相對較小的差異,但是加載很多類或大量使用String.intern()方法的較大應用程序將會看到更顯着的差異。

對此的詳細解釋可以在此answer上找到。

2

當我們實習一個字符串時,我們確保該字符串的所有用法都指向同一個實例。

不完全是。當你這樣做:

String s2 = s1.intern(); 

你正在做的是確保s2String在字符串池中。這不會影響s1或任何其他String引用或變量中的值。如果你想讓字符串的其他副本被實現,你需要明確地做到這一點......或者將實際的字符串引用分配給相應的變量。

我會假設底層字符串對象在堆中。

這是正確的。它可能位於「permgen」堆或常規堆中,具體取決於您使用的Java版本。但它總是「堆在一起」。

但是,存儲在存儲器中的引用變量在哪裏?

「引用變量」...即保存從調用intern() ...獲得的引用的引用變量與任何其他變量沒有區別。它可以是

  • 局部變量或參數(在一個堆棧幀保持),
  • 實例字段(在常規堆對象保持),
  • 靜態字段(在PermGen的堆對象保持)...甚至
  • 一個jstring變量或JNI代碼(類似於舉行的「別處」。)

事實上,典型的JVM使用私有哈希表來保存到實習字符串的引用,它使用JVM的弱點如果沒有別的東西在使用它們,可以確保被攔截的字符串可以被垃圾回收。

它是否具有與靜態相同的行爲 - 其中引用存儲在permgen中,並且只有在類加載器(和應用程序)退出後才使得字符串實例可用於gc?

通常不......見上文。

在大多數Java平臺中,實際的字符串可以像其他字符串一樣被垃圾收集。如果被攔截的字符串存儲在「permgen」空間中,則可能需要較長的時間才能對該對象進行垃圾收集,因爲「permgen」不經常收集。但是,實字符串的生命週期並不與類加載器的生命週期等相關。

+0

一個'static'字符串不一定是一個字符串文字。 OP在這一點上似乎也很困惑。 –

+0

@TimBender - 正確...他很可能會。但是我沒有從他寫的內容中清楚地得到這種印象。 –

相關問題