为什么string.intern()这么慢?

dag*_*ies 33 java string performance

在任何人对使用的事实提出质疑之前string.intern(),请允许我说在我的特定应用程序中出于内存和性能原因需要它.[1]

所以,直到现在我使用String.intern()并假设它是最有效的方法.但是,我注意到它已经成为软件的瓶颈.[2]

然后,就在最近,我试图String.intern()用一个巨大的地图替换我放置/获取字符串,以便每次获得一个唯一的实例.我预计这会慢一点......但恰恰相反!它速度非常快!intern()通过推动/轮询地图(实现完全相同)来替换,导致速度提高了一个数量级以上.

问题是:为什么intern()这么慢?!?那么为什么它不是简单地由地图(实际上只是一个定制的集合)备份而且速度会快得多?我很困惑.

[1]:对于不相信的人:它是在自然语言处理中并且必须处理千兆字节的文本,因此需要避免相同字符串的许多实例以避免炸毁内存和引用字符串比较足够快.

[2]:没有它(正常的字符串)是不可能的,有了它,这个特定的步骤仍然是计算密集程度最高的一步

编辑:

由于对这篇文章的惊人兴趣,这里有一些代码来测试它:

http://pastebin.com/4CD8ac69

而实习结果超过100万字符串:

  • HashMap:4秒
  • String.intern():54秒

由于避免了一些预热/ OS IO缓存和类似的东西,通过颠倒两个基准的顺序重复实验:

  • String.intern():69秒
  • HashMap:3秒

如你所见,差异非常显着,超过十倍.(使用OpenJDK 1.6.0_22 64位...但使用太阳一个导致类似的结果我认为)

Mar*_*ano 6

文章讨论的实施String.intern().在Java 6和7中,实现使用固定大小(1009)哈希表,因此数字条目增长,性能变为O(n).可以使用更改固定大小-XX:StringTableSize=N.显然,在Java8中,默认大小较大但问题仍然存在.


Mic*_*rdt 4

性能差异最可能的原因是:String.intern()是本机方法,调用本机方法会产生大量开销。

那么为什么它是本地方法呢?可能是因为它使用常量池,这是一个低级 VM 构造。

  • @Arnaud:一点也不。在 Java 的早期,当 JVM 速度慢得多时,出于性能原因使用本机方法可能是合理的。但这种情况在十多年前发生了变化。如今,使用 JNI 的唯一原因几乎是访问不属于 Java 标准 API 的功能。 (6认同)
  • 我可以肯定地告诉你,它慢的原因并不是因为它是本地方法。如果这就是问题所在,那么无论字符串池的大小如何,您都希望付出相同的性能损失(跨越 JVM 原生障碍)。我的基准测试(http://stackoverflow.com/questions/10624232)显示 String.intern() 的复杂度为 O(n^2),其中 n 是池中字符串的数量。这个问题的真正答案是: String.intern 使用的算法很糟糕并且无法扩展。 (4认同)
  • 也许您错过了这一点:“标准库中的本机方法不一定要通过 JNI”。JNI 很贵。调用属于 JDK 一部分的本机方法非常便宜。 (4认同)