很多人谈论String.intern()的性能优势,但实际上我更感兴趣的是性能损失可能是什么。
我的主要关切是:
我对所有这些事情都很关心,因为我目前正在开发一个财务应用程序,该应用程序由于重复的String而使用过多的内存。有些字符串基本上看起来像枚举值,并且只能有有限数量的潜在值(例如货币名(“美元”,"EUR"))存在于100多万份副本中。在本例中,String.intern()似乎是一个不需要考虑的问题,但我担心每次在某个地方存储货币时调用intern()的同步开销。
除此之外,一些其他类型的字符串可以具有数百万个不同的值,但每个字符串仍然有数万个副本(如ISIN代码)。对于这些,我担心的是,一个百万字符串的实习生将基本减缓intern()方法的速度,从而使我的应用程序陷入困境。
发布于 2012-05-17 01:19:36
我给自己做了一点基准测试。对于搜索成本部分,我决定将String.intern()与ConcurrentHashMap.putIfAbsent(s,s)进行比较。基本上,这两个方法所做的事情是相同的,但String.intern()是一个本地方法,它存储并从JVM中直接管理的SymbolTable中读取数据,而ConcurrentHashMap.putIfAbsent()只是一个普通的实例方法。
您可以在github gist上找到基准代码(因为缺少一个更好的地方来放置它)。您还可以在源文件顶部的注释中找到我在启动JVM时使用的选项(以验证基准没有倾斜)。
不管怎么说,以下是结果:
搜索成本(单线程)
传奇
String.intern()
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 7ConcurrentHashMap.putIfAbsent()
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()。
发布于 2013-08-25 08:10:31
我最近写了一篇关于Java6、7和8: String.intern()实现的文章:Java6、7和8中的String.intern -字符串池。
有一个-XX:StringTableSize JVM参数,它允许您使String.intern在Java7+中非常有用。因此,不幸的是,我不得不说,这个问题目前给读者提供了误导的信息。
发布于 2012-05-16 18:16:30
与重用String.intern()相比,我发现最好使用快速散列表并进行自己的实习。使用我自己的哈希表意味着我可以自己做出关于并发性的决定,而不是竞争PermGen空间。
我这么做是因为我正在处理一个问题,这个问题有数百万个字符串,很多是相同的,我想(a)减少内存占用,(b)允许通过身份进行比较。对于我的问题,使用我的非String.intern()方法,实习比没有实习要好。
YMMV
https://stackoverflow.com/questions/10624232
复制相似问题