Lor*_*igs 41 java string performance
很多人都在谈论String.intern()的性能优势,但实际上我对性能损失可能更感兴趣.
我主要担心的是:
我关注所有这些事情,因为我目前正在对使用具有复制,因为字符串太多内存的问题,一个金融应用程序.某些字符串基本上看起来像枚举值,并且只能存在数量有限的潜在值(例如货币名称("USD","EUR"))超过一百万份.在这种情况下,String.intern()似乎是不费吹灰之力,但我担心每次在某处存储货币时调用intern()的同步开销.
最重要的是,一些其他类型的字符串可以具有数百万个不同的值,但每个字符串仍然有数万个副本(例如ISIN代码).对于这些,我担心实习百万串基本上会减慢实习生()方法这么多,以拖垮我的应用程序.
Lor*_*igs 39
我自己做了一些基准测试.对于搜索成本部分,我决定将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 7
Run Code Online (Sandbox Code Playgroud)
ConcurrentHashMap.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
Run Code Online (Sandbox Code Playgroud)
搜索成本的结论:String.intern()的调用成本高得惊人.它在O(n)中非常严重,其中n是池中字符串的数量.当池中的字符串数量增加时,从池中查找一个字符串的时间量会增长得更多(每次查找0.7微秒,10'000个字符串,每次查找40微秒,1'000'000个字符串).
ConcurrentHashMap按预期进行扩展,池中的字符串数量对查找速度没有影响.
根据这个实验,我强烈建议如果要实习多个字符串,请避免使用String.intern().
小智 21
我最近在Java 6,7和8中编写了一篇关于String.intern()实现的文章:Java 6,7和8中的 String.intern - 字符串池.
有一个-XX:StringTableSize JVM参数,它允许你使String.intern在Java7 +中非常有用.所以,不幸的是,我不得不说这个问题目前正在向读者提供误导性的信息.
我发现最好使用fastutil哈希表并自己进行实习而不是重用String.intern()
。使用我自己的哈希表意味着我可以对并发做出自己的决定,并且我不争夺PermGen空间。
我之所以这样做,是因为我正在研究一个问题,该问题实际上有数百万个字符串,许多相同,并且我想(a)减少占用空间,(b)允许按标识进行比较。对于我的问题,使用我的notString.intern()
方法,实习比没有好。
YMMV。