当我们实习一个字符串时,我们确保该字符串的所有使用都引用同一个实例。
我会假设底层字符串对象在堆中。
但是,引用变量存储在内存中的什么位置?
static
它是否具有与- 其中引用存储在 permgen 中并且仅在类加载器(和应用程序)退出后才使字符串实例可用于 gc 的行为相同的行为?
当我们实习一个字符串时,我们确保该字符串的所有使用都引用同一个实例。
我会假设底层字符串对象在堆中。
但是,引用变量存储在内存中的什么位置?
static
它是否具有与- 其中引用存储在 permgen 中并且仅在类加载器(和应用程序)退出后才使字符串实例可用于 gc 的行为相同的行为?
在 JDK 6 之前,Intern'ed 字符串存储在内存池中称为永久代的地方,这是 JVM 中为非用户对象(如类、方法和其他内部 JVM 对象)保留的区域。这个区域的大小是有限的,通常比堆小得多。
从 JDK 7 开始,interned 字符串不再分配在 Java 堆的永久代中,而是与应用程序创建的其他对象一起分配在 Java 堆的主要部分(称为年轻代和年老代)中. 此更改将导致更多数据驻留在主 Java 堆中,而永久代中的数据更少,因此可能需要调整堆大小。由于此更改,大多数应用程序只会看到相对较小的堆使用差异,但加载许多类或大量使用 String.intern() 方法的大型应用程序将看到更显着的差异。
可以在这个答案中找到对此的详细解释。
当我们实习一个字符串时,我们确保该字符串的所有使用都引用同一个实例。
不完全是。当你这样做时:
String s2 = s1.intern();
您正在做的是确保在字符串池中s2
引用 a String
。这不会影响 中的值s1
或任何其他String
引用或变量。如果您希望保留字符串的其他副本,则需要显式执行此操作...或将已保留的字符串引用分配给相应的变量。
我会假设底层字符串对象在堆中。
那是对的。它可能位于“permgen”堆或常规堆中,具体取决于您使用的 Java 版本。但它总是“在堆中”。
但是,引用变量存储在内存中的什么位置?
“引用变量” ...即保存您从调用中获得的引用的那个intern()
...与任何其他变量没有什么不同。有可能
jstring
变量或类似变量(在“其他地方”保存。)实际上,典型的 JVM 使用私有哈希表来保存对实习字符串的引用,并且它使用 JVM 的弱引用机制来确保如果没有其他人使用它们,可以对实习字符串进行垃圾收集。
它是否具有与静态相同的行为 - 其中引用存储在 permgen 中并且仅在类加载器(和应用程序)退出后才使字符串实例可用于 gc?
通常没有......见上文。
在大多数 Java 平台中,实习字符串可以像其他字符串一样被垃圾收集。如果实习字符串存储在“permgen”空间中,对象被垃圾回收可能需要更长的时间,因为“permgen”很少被收集。但是,实习字符串的生命周期与类加载器的生命周期等无关。