首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >String.intern()的性能惩罚

String.intern()的性能惩罚
EN

Stack Overflow用户
提问于 2012-05-16 18:10:20
回答 5查看 11.5K关注 0票数 45

很多人谈论String.intern()的性能优势,但实际上我更感兴趣的是性能损失可能是什么。

我的主要关切是:

  • 搜索成本: intern()用于计算常量池中是否存在可持续字符串所需的时间。用池中字符串的数量来衡量成本是怎样的?
  • 同步:显然,常量池是由整个JVM共享的。当intern()从多个线程一次又一次地被调用时,这个池是如何运行的?它执行了多少锁定?如何对竞争进行绩效评估?

我对所有这些事情都很关心,因为我目前正在开发一个财务应用程序,该应用程序由于重复的String而使用过多的内存。有些字符串基本上看起来像枚举值,并且只能有有限数量的潜在值(例如货币名(“美元”,"EUR"))存在于100多万份副本中。在本例中,String.intern()似乎是一个不需要考虑的问题,但我担心每次在某个地方存储货币时调用intern()的同步开销。

除此之外,一些其他类型的字符串可以具有数百万个不同的值,但每个字符串仍然有数万个副本(如ISIN代码)。对于这些,我担心的是,一个百万字符串的实习生将基本减缓intern()方法的速度,从而使我的应用程序陷入困境。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-05-17 01:19:36

我给自己做了一点基准测试。对于搜索成本部分,我决定将String.intern()与ConcurrentHashMap.putIfAbsent(s,s)进行比较。基本上,这两个方法所做的事情是相同的,但String.intern()是一个本地方法,它存储并从JVM中直接管理的SymbolTable中读取数据,而ConcurrentHashMap.putIfAbsent()只是一个普通的实例方法。

您可以在github gist上找到基准代码(因为缺少一个更好的地方来放置它)。您还可以在源文件顶部的注释中找到我在启动JVM时使用的选项(以验证基准没有倾斜)。

不管怎么说,以下是结果:

搜索成本(单线程)

传奇

  • 计数:我们试图汇集的不同字符串的数目。
  • 初始实习生:在字符串池中插入所有字符串所需的ms时间。
  • 查找相同的字符串:使用与以前在池中输入的完全相同的实例,从池中再次查找每个字符串所需的ms时间。
  • 查找相等字符串:在ms中重新从池中查找每个字符串所需的时间,但使用不同的实例。

String.intern()

代码语言:javascript
复制
count       initial intern   lookup same string  lookup equal string
1'000'000            40206                34698                35000
  400'000             5198                 4481                 4477
  200'000              955                  828                  803
  100'000              234                  215                  220
   80'000              110                   94                   99
   40'000               52                   30                   32
   20'000               20                   10                   13
   10'000                7                    5                    7

ConcurrentHashMap.putIfAbsent()

代码语言:javascript
复制
count       initial intern   lookup same string  lookup equal string
1'000'000              411                  246                  309
  800'000              352                  194                  229
  400'000              162                   95                  114
  200'000               78                   50                   55
  100'000               41                   28                   28
   80'000               31                   23                   22
   40'000               20                   14                   16
   20'000               12                    6                    7
   10'000                9                    5                    3

搜索成本的结论是:调用String.intern()非常昂贵。它缩放得非常糟糕,在O(n)中,n是池中字符串的数目。当池中的字符串数量增加时,从池中查找一个字符串的时间会增长得多(每次查找10'000字符串的时间为0.7微秒,1‘000’字符串的每次查找时间为40微秒)。

ConcurrentHashMap按预期缩放,池中的字符串数对查找速度没有影响。

基于这个实验,我强烈建议,如果要实习生超过几个字符串,就应该避免使用String.intern()。

票数 40
EN

Stack Overflow用户

发布于 2013-08-25 08:10:31

我最近写了一篇关于Java6、7和8: String.intern()实现的文章:Java6、7和8中的String.intern -字符串池

有一个-XX:StringTableSize JVM参数,它允许您使String.intern在Java7+中非常有用。因此,不幸的是,我不得不说,这个问题目前给读者提供了误导的信息。

票数 24
EN

Stack Overflow用户

发布于 2012-05-16 18:16:30

与重用String.intern()相比,我发现最好使用快速散列表并进行自己的实习。使用我自己的哈希表意味着我可以自己做出关于并发性的决定,而不是竞争PermGen空间。

我这么做是因为我正在处理一个问题,这个问题有数百万个字符串,很多是相同的,我想(a)减少内存占用,(b)允许通过身份进行比较。对于我的问题,使用我的非String.intern()方法,实习比没有实习要好。

YMMV

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10624232

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档