【问题标题】:Am I correctly interning my Strings?我是否正确地实习我的字符串?
【发布时间】:2009-05-29 06:03:06
【问题描述】:

我想确保我不会破坏 permgen 空间,所以我正在仔细地实习我的字符串。

这两个语句是等价的吗?

String s1 = ( "hello" + "world" ).intern(); 

String s2 = "hello".intern() + "world".intern();

更新

我提出问题的方式与实际应用完全不同。这是我使用实习生的方法。

public String toAddress( Transport transport )
{
    Constraint.NonNullArgument.check( transport, "transport" );

    switch( transport )
    {
    case GOOGLE:
    case MSN:
        return ( transport.code() + PERIOD + _domain ).intern();
    case YAHOO:
    default:
        return _domain;
    }
}
private String _domain;  // is initialized during constructor
private static final String PERIOD = ".";

【问题讨论】:

    标签: java memory-management


    【解决方案1】:

    我能想到的最好的建议是:不要打扰。静态声明的字符串无论如何都将在常量池中,除非您动态创建一个...错误的字符串,不,我想不出原因。

    自 97 年以来我一直在使用 Java 进行编程,但我从未真正使用过 String.intern()

    编辑:看到你的更新后,我真的认为你不应该使用实习生()。您的方法看起来非常正常,几乎没有理由使用 intern()。

    我这样做的原因是它感染了优化,并且可能是过早的优化,你在猜测垃圾收集器。如果你的方法是短暂的,那么生成的字符串将在下一次次要 GC 中很快在年轻一代中死去,如果不是这样,它无论如何都会在成熟一代中被实习(因为需要更好的词) .

    我想这可能是一个好主意的唯一情况是,如果您花一点时间使用分析器并证明它对您的应用程序的性能有很大的影响。

    【讨论】:

    • intern() 并不邪恶……你只是不需要它
    • 我用 Java 编程多年,只使用了两次 intern(),同时对一些需要支持尽可能多的会话的基于服务器的软件进行了非常彻底的性能优化。 99.99% 的情况下你永远不应该使用它,如果你确实找到了一个有意义的地方,请务必考虑对你的 permgen 空间的影响:你只想实习小的、有界的文字集。
    • 不能(也没有)说得更好。
    • 伙计们,字符串重复是常态(不确定这是否是最初的问题。Jacques 非常友好地已经发布了指向我的博客的链接。您可以在流行的文章中找到大量字符串重复的示例Netbeans 和 Eclipse 等应用程序。String.intern() 可用于避免重复。有可能的解决方案,但它们通常内存效率较低
    【解决方案2】:

    正如 jensgram 所说,这两个语句是不等价的。两条重要规则:

    • 在代码中连接字符串文字以字符串常量结尾,因此这两个语句完全等价(它们将产生相同的字节码):

      String x = "foo" + "bar":
      String x = "foobar";
      
    • 字符串常量是自动实习的,你不需要显式地这样做

    现在,这集中在文字上——您是实际上在文字上调用intern,还是您的实际用例有些不同(例如,从您经常看到的数据库中获取的实习值) ?如果有,请提供更多详细信息。

    编辑:好的,根据问题编辑:这可以节省一些内存如果您最终将toAddress()的返回值存储在它会粘住的地方很长一段时间并且你最终会多次使用相同的地址。如果这些不是,实习实际上可能会让事情变得更糟。我不确定被实习的字符串是否会永远存在,但很有可能。

    在我看来,这不太可能很好地利用实习,而且很可能会让事情变得更糟。你提到试图节省 permgen 空间 - 为什么你认为实习会有所帮助?无论如何,连接的字符串不会以 permgen 结尾,除非我错了。

    【讨论】:

    • 内部字符串被回收。在 SUN JVM 上存储在 permspace 中,这意味着它们需要完全 GC 来回收
    【解决方案3】:

    没有。将两个实习字符串加在一起不会得到一个实习字符串。

    也就是说,很少有人需要“仔细地练习琴弦”。除非您要处理大量相同的字符串,否则麻烦大于价值。

    【讨论】:

    • 再次,javac 进行连接,因此“helloworld”已经被实习了。使用 javap -c 来查看。
    • javac 进行第一个连接,但不是后者。问题不在于 ("hello" + "world").intern() 是否等同于 "helloworld"。问题是那个(实习的)字符串是否等同于“hello”.intern()+“world”.intern()。答案是否定的,因为 javac 不会不断地将后一个表达式折叠成“helloworld”(可能是由于中间的方法调用),并且将两个实习字符串对象连接在一起不会给你一个实习字符串。
    【解决方案4】:

    我会说不。 s1 将“helloworld”添加到池中,而 s2 由两个池化字符串“hello”和“world”组成。

    【讨论】:

    • javac 进行连接,因此“helloworld”已经被实习了。
    【解决方案5】:

    更多信息将帮助我们理解您的查询...无论如何...

    如果您想手动为 HelloWorld 实习,那么请使用第一个语句,就像在第二个语句中一样,您分别实习 hello 和 world。两个语句根本不相同。

    【讨论】:

      【解决方案6】:

      在编写所有这样的代码之前,您可能希望获得某种形式的证据(也许通过分析)您正在“打击 permgen 空间”。

      否则,您可能只是在做“过早的优化”,而这通常是不受欢迎的。 请参阅http://en.wikipedia.org/wiki/Optimization_(computer_science)#When_to_optimize 了解更多详情,了解为什么这可能是一件坏事。

      【讨论】:

        【解决方案7】:

        在许多情况下,“仔细地实习”你的字符串只会浪费一些时间。 考虑以下情况:

        void foobar(int x) {
          String s1 = someMethod(x).intern();
          ...
          ...
        }
        

        所以 s1 是实习的,没有(堆)空间浪费?错误的!最有可能的是, someMethod(x) 的中间结果仍然存在于堆中的某个位置,需要进行垃圾回收。那是因为 someMethod() 以某种方式构造了字符串,并且(除非它返回一个文字)它在堆上做到了。但是然后...更好地查看 permgen 空间的用途。它用于关于类的元数据和(哎呀)String.intern 表。通过实习所有字符串,你正在做你想要避免的事情:冲击 permgen 空间。

        更多信息在这里:http://www.thesorensens.org/2006/09/09/java-permgen-space-stringintern-xml-parsing/

        【讨论】:

          【解决方案8】:

          您使用的字符串数量对 JVM 的永久生成没有影响,因为我们仍在讨论一个

          【讨论】:

          • 它们以前是在 perm gen 中创建的(不完全确定当前状态是什么)。
          • 如果您在谈论 PermGen,我会假设您使用的是 Sun JVM。请问是哪个版本的?
          【解决方案9】:

          实习字符串基本上是等待发生的内存泄漏:(

          除非您有非常非常好的理由[1],否则不要这样做,而是将其留给 JVM。

          [1] 如,“亲爱的老板,请不要解雇我。我有这些分析数据来支持我决定使用实习生”:)

          【讨论】:

            猜你喜欢
            • 2013-12-15
            • 1970-01-01
            • 2013-07-14
            • 2019-06-30
            • 1970-01-01
            • 2023-03-11
            • 1970-01-01
            • 2012-09-02
            • 2012-05-27
            相关资源
            最近更新 更多