String.intern() 的垃圾收集行为

问题描述 投票:0回答:4

如果我使用 String.intern() 来提高性能,因为我可以使用“==”来比较实习字符串,我会遇到垃圾收集问题吗?内部字符串的垃圾回收机制与普通字符串有何不同?

java performance string garbage-collection
4个回答
21
投票

String.intern()
管理一个内部的、本机实现的池,它具有一些与 GC 相关的特殊功能。这是旧代码,但如果重新实现,它将使用
java.util.WeakHashMap
。弱引用是一种保留指向对象的指针而不阻止其被收集的方法。对于统一池(例如实习字符串)来说正是正确的选择。

可以使用以下 Java 代码演示驻留字符串是否被垃圾回收:

public class InternedStringsAreCollected {

    public static void main(String[] args)
    {
        for (int i = 0; i < 30; i ++) {
            foo();  
            System.gc();
        }   
    }

    private static void foo()
    {
        char[] tc = new char[10];
        for (int i = 0; i < tc.length; i ++)
            tc[i] = (char)(i * 136757);
        String s = new String(tc).intern();
        System.out.println(System.identityHashCode(s));
    }
}

此代码创建 30 次相同的字符串,每次都会对其进行实习。此外,它还使用

System.identityHashCode()
来显示
Object.hashCode()
在该保留字符串上返回的哈希码。运行时,此代码会打印出不同的整数值,这意味着您不会每次都获得相同的实例。

无论如何,不鼓励使用

String.intern()
。它是一个共享静态池,这意味着它很容易成为多核系统上的瓶颈。使用
String.equals()
比较字符串,你会活得更长久、更快乐。


10
投票

事实上,这不是垃圾收集优化,而是字符串池优化。 当您调用

String.intern()
时,您将对初始字符串的引用替换为其基本引用(第一次遇到该字符串的引用,如果尚不知道则为该引用)。

在 Java 7 之前,内部字符串是在 PermGen 空间中分配的。一旦您的字符串在应用程序中不再使用,这将成为垃圾收集器问题,因为内部字符串池是 String 类的静态成员,并且永远不会被垃圾收集。从 Java 7 开始,驻留字符串分配在 Heap 上并接受垃圾回收。

根据经验,我认为最好从不使用此实习生方法,并让编译器仅将其用于常量字符串,这些常量字符串如下声明:

String myString = "a constant that will be interned";

这更好,从某种意义上说,它不会让你做出错误的假设

==
可以工作,但它不会。

此外,事实是

String.equals
本质上调用
==
作为优化,确保在幕后使用内部字符串优化。这是又一个证据
==
不应该永远 用于字符串。


8
投票

这篇文章提供了完整的答案。

在java 6中,字符串池驻留在PermGen中,从java 7开始,字符串池驻留在堆内存中。

手动驻留的字符串将被垃圾收集。
仅当定义字符串文字的类被卸载时,字符串文字才会被垃圾收集。

字符串池是一个固定大小的HashMap,在java 6和java 7早期版本中很小,但从java 7u40开始增加到60013。
可以使用 -XX:StringTableSize= 进行更改,并使用 -XX:+PrintFlagsFinal java 选项进行查看。


0
投票

请阅读:http://satukubik.com/2009/01/06/java-tips-memory-optimization-for-string/

从你的信息中我能得到的结论是:你实习了太多的String。如果你确实需要实习这么多 String 来优化性能,增加 perm gen 内存,但如果我是你,我会先检查是否真的需要这么多实习字符串。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.