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

2022-09-01 09:06:08

在有人质疑使用的事实之前,让我说,出于内存和性能原因,我在特定的应用程序中需要它。[注1]string.intern()

所以,直到现在,我一直使用并认为这是最有效的方法。但是,我注意到这是软件中的瓶颈。[注2]String.intern()

然后,就在最近,我试图用一个巨大的地图来替换,我在其中放置/获取字符串,以便每次都获得一个唯一的实例。我预计这会更慢...但事实恰恰相反!它的速度快得多!通过推送/轮询地图(实现完全相同)来替换,可以加快一个数量级以上。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 位 ...但是使用太阳一个导致了类似的结果,我认为)


答案 1

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


答案 2

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

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