1

当我们实习一个字符串时,我们确保该字符串的所有使用都引用同一个实例。

我会假设底层字符串对象在堆中。

但是,引用变量存储在内存中的什么位置?

static它是否具有与- 其中引用存储在 permgen 中并且仅在类加载器(和应用程序)退出后才使字符串实例可用于 gc 的行为相同的行为?

4

2 回答 2

5

在 JDK 6 之前,Intern'ed 字符串存储在内存池中称为永久代的地方,这是 JVM 中为非用户对象(如类、方法和其他内部 JVM 对象)保留的区域。这个区域的大小是有限的,通常比堆小得多。

从 JDK 7 开始,interned 字符串不再分配在 Java 堆的永久代中,而是与应用程序创建的其他对象一起分配在 Java 堆的主要部分(称为年轻代和年老代)中. 此更改将导致更多数据驻留在主 Java 堆中,而永久代中的数据更少,因此可能需要调整堆大小。由于此更改,大多数应用程序只会看到相对较小的堆使用差异,但加载许多类或大量使用 String.intern() 方法的大型应用程序将看到更显着的差异。

可以在这个答案中找到对此的详细解释。

于 2013-05-31T02:48:16.357 回答
2

当我们实习一个字符串时,我们确保该字符串的所有使用都引用同一个实例。

不完全是。当你这样做时:

    String s2 = s1.intern();

您正在做的是确保在字符串池中s2引用 a String。这不会影响 中的值s1或任何其他String引用或变量。如果您希望保留字符串的其他副本,则需要显式执行此操作...或将已保留的字符串引用分配给相应的变量。

我会假设底层字符串对象在堆中。

那是对的。它可能位于“permgen”堆或常规堆中,具体取决于您使用的 Java 版本。但它总是“在堆中”。

但是,引用变量存储在内存中的什么位置?

“引用变量” ...即保存您从调用中获得的引用的那个intern()...与任何其他变量没有什么不同。有可能

  • 局部变量或参数(保存在堆栈帧中),
  • 实例字段(保存在常规堆对象中),
  • 一个静态字段(保存在 permgen 堆对象中)......甚至
  • JNI 代码中的jstring变量或类似变量(在“其他地方”保存。)

实际上,典型的 JVM 使用私有哈希表来保存对实习字符串的引用,并且它使用 JVM 的弱引用机制来确保如果没有其他人使用它们,可以对实习字符串进行垃圾收集。

它是否具有与静态相同的行为 - 其中引用存储在 permgen 中并且仅在类加载器(和应用程序)退出后才使字符串实例可用于 gc?

通常没有......见上文。

在大多数 Java 平台中,实习字符串可以像其他字符串一样被垃圾收集。如果实习字符串存储在“permgen”空间中,对象被垃圾回收可能需要更长的时间,因为“permgen”很少被收集。但是,实习字符串的生命周期与类加载器的生命周期等无关。

于 2013-05-31T03:09:11.283 回答