AbstractConcurrentMap是Groovy中的核心类,它用于存储在运行时添加到Groovy类的动态属性。我使用Grails 2.1.2和Groovy 1.8.8,但我认为所有Groovy版本都存在该问题(链接源代码适用于Groovy 2.4.3版)。
问题发生在内部类段put()方法(第105行)中:
当前计数较大时,映射的阈值为rehash()。现在棘手的部分是,Map包含对对象的软引用,rehash()验证这些引用。因此,当GC丢弃软引用时,生成的段不会扩展(如put()方法中所假设的那样)。
在last line of rehash()中,Segmen的内部计数器已更新count = newCount
(这是"有效"无遗留引用的数量,可能比以前更小按上述计算)
rehash()完成后,put()方法会继续,但有缺陷的部分是,它忽略了内部count
的先前设置,并设置了之前的计数在124,143和159
所以发生了以下步骤:
threshold = 786432; count=786432
count = 786433; threshold = 786432
count = 486 000
count = 486 000
并将计数设置为count = 786433
当在多线程环境中发生这种情况时,所有其他线程都在等待(停放)lock(),直到rehash()和put()完成(然后下一个线程再次执行rehash())。您可以想象这对性能有何影响...
我不明白这个错误如何能够存活很多版本,尽管该类被广泛使用,但没有人注意到。也许我错过了什么?
建议的解决方案:
重新散列完成后更新c变量。 在第105行和第106行之间添加:
c = count + 1
答案 0 :(得分:0)
该错误已在Groovy JIRA https://issues.apache.org/jira/browse/GROOVY-7448上报告,现已修复。
Fix Version/s:
2.4.4, 2.5.0-beta-1