java - 如果 Java 字符串是不可变的而 StringBuilder 是可变的,为什么它们在我的代码中浪费了相同数量的内存?

标签 java string immutability

我运行了这些代码,我遇到了一些问题,这有点奇怪。

使用字符串:

while(true)
{
    String s = String.valueOf(System.currentTimeMillis());
    System.out.println(s);
    Thread.sleep(10);
}

使用 StringBuilder:

StringBuilder s = null;
    while(true)
    {
        s = new StringBuilder();
        s.append(System.currentTimeInMillis());
        System.out.println(s);
        Thread.sleep(10);
    }

在这两种情况下,他们都陷入了 12540 K 的内存浪费。在 Windows XP SP2 上运行此测试。

为什么他们要浪费同样数量的内存? 为什么不可变字符串不再浪费内存? 题外话:如何将 StringBuilder 转换为以特定字符集编码的字节数组?

最佳答案

很难弄清楚您在这里实际问的是什么,但应用程序的行为完全符合我的预期。

Strings are immutable and the garbage collector doesn't take them out. isn't it

可变和不可变对象(immutable对象)都可能在 Java 中被垃圾回收。

确定对象是否真正被垃圾回收的实际标准是可达性。简单来说,当垃圾收集器发现应用程序不能再使用某个对象时,该对象将被删除。

在您的两个应用程序中,每 10 毫秒创建一次大小大致相同的对象。在每次迭代中,都会创建一个新对象并将其引用分配给 s,以替换先前的引用。这使得之前的对象无法访问,并且有资格进行垃圾回收。在某个时候,Java VM 决定运行垃圾收集器。这摆脱了所有无法访问的对象......并且应用程序继续。

I read that common Strings are not collected ever by the garbage collector, is that false?

这在两个方面是错误的:

  • new String(...)String.substring(...)1等创建的字符串与任何其他 Java 对象没有区别。

  • interned(通过调用 String.intern())的字符串存储在 PermGen 堆中的字符串池中2 。然而,即使是 PermGen 堆也会被垃圾回收,尽管时间尺度比正常创建对象的堆更长。

(曾几何时,PermGen 堆没有被垃圾回收,但很久以前就改变了。)

正如@MichaelBorgwardt 正确识别的那样,您将字符串对象(通常)与对应于字符串文字的字符串对象混淆了。后者会自动驻留,并最终进入字符串池。但是,它们可能仍要进行垃圾回收。如果父类被卸载并且没有其他内容引用文字,就会发生这种情况。


1 - 在 Java 6 和更早版本中,使用 new String 和使用 String.substring 创建的字符串是有区别的。在后一种情况下,原始字符串和子字符串将共享保存字符串字符的后备数组。在 Java 7 中,这发生了变化。 String.substring 现在创建一个新的后备数组。

2 - 从 Java 7 开始,字符串池只是普通堆中的一个(隐藏)数据结构。从 Java 8 开始,PermGen 堆不再存在。

关于java - 如果 Java 字符串是不可变的而 StringBuilder 是可变的,为什么它们在我的代码中浪费了相同数量的内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3967646/

相关文章:

java - 部署 Spring 4.0.1 应用程序失败

java - jsoup可以处理元刷新重定向吗

带有可变十进制数说明符的 Python f 字符串

c++ - 我的函数无法正确编译

java - Java中可变对象的封装

java - Guava 不可变集合有用还是只是额外的开销?

tree - 本地编辑纯功能树

java - 确定字符串中的每个字符是否包含全角字符

java - 无法读取 Artifact org.apache.maven.plugins :maven-install-plugin:maven-plugin:2. 4:runtime 的生命周期映射元数据

.net - Regex.IsMatch 与 string.Contains