Groovy中的Bug AbstractConcurrentMap? [英] Bug in Groovy AbstractConcurrentMap?

查看:127
本文介绍了Groovy中的Bug AbstractConcurrentMap?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

AbstractConcurrentMap 是Groovy中的核心类,它用于存储在运行时添加到Groovy类中的动态属性。我在Groovy 1.8.8中使用了Grails 2.1.2,但我认为这个问题出现在所有的Groovy版本中(链接的源代码是针对Groovy 2.4.3的版本的)。



问题发生在内部类的细分 put()方法(第105行):


  • 如果当前计数大于地图的阈值a rehash()发生。现在棘手的部分是,该地图拥有对象的软引用和 rehash()验证这些引用。因此,当GC放弃软引用时,结果段不会扩展(如 put()方法)。


  • rehash()的最后一行 Segmen't内部计数器更新 count = newCount (这是活着的未被发现的引用的数量,并且可以小于上面描述的前一次计数)


  • rehash() 完成后, put()方法仍在继续,但是错误的部分是,它忽略了以前的设置内部的 count ,它在每行 124 143 159




正在发生:


  1. 地图状态: threshold = 786432; count = 786432

  2. 将新元素插入到映射中: count = 786433;阈值= 786432

  3. 因为新的计数会大于阈值 rehash()发生

  4. rehash()发现大多数对象都是垃圾回收,因此它不会增加Segment的大小,但无论如何它会将所有对象从一个表复制到另一个表(System.arrayCopy() )。
  5. rehash()将内部计数设置为较小的值,因为许多对象都是垃圾收集的(软引用),可以这样说: count = 486 000

  6. put()继续,忽略 count = 486 000 并将计数设置为 count = 786433

  7. Anot她的元素被插入,但是在这种状态下,计数仍然大于阈值,所以再次发生重新刷新

  8. 从现在起,添加到地图的每个元素都会触发一个 rehash(),这对性能有很大的影响。

在多线程环境中发生这种情况时,所有其他线程正在等待(停放)lock(),直到rehash()和put()完成(然后下一个再次执行rehash())。你可以想象这会对性能产生什么样的影响... ...

我不明白这个bug如何能够在没有人注意的情况下生存下如此多的版本,尽管这个类被广泛使用。也许我错过了什么?



建议的解决方案: 更新c rehash完成后变量。
在第105行和第106行之间添加:

  c = count + 1 


解决方案

这个bug在Groovy JIRA https://issues.apache.org/jira/browse/GROOVY-7448 现在已修复。

 修正版本:
2.4.4,2.5.0-beta-1
code>


AbstractConcurrentMap is a core class in Groovy, it is used for storing dynamic properties added to Groovy classes during runtime. I'm using Grails 2.1.2 with Groovy 1.8.8, but I think the issue is present in all Groovy versions (the linked source code is for Groovy version 2.4.3).

The problem happens in inner class Segment's put() method (line 105):

  • When the current count is greater then map's threshold a rehash() happens. Now the tricky part is, that the Map holds soft references to objects and rehash() validates those references. So when GC discards soft references, the resulting segment doesn't expand (as it is assumed in the put() method).

  • in the last line of rehash() the Segmen't internal counter is updated count = newCount (which is the number of "alive" undiscarded references and can be smaller than previous count as described above)

  • after rehash() is done, the put() method continues, however the buggy part is, that it disregards the previous setting of the internal count and it sets the previous count+1 value in every case on lines 124, 143 and 159

So the following steps are happening:

  1. Map state: threshold = 786432; count=786432
  2. New element is inserted into the map: count = 786433; threshold = 786432
  3. since new count would be greater than threshold rehash() happens
  4. rehash() finds out, that most of the objects are garbage collected, thus it doesn't increase the size of the Segment, however anyway it copies all the objects from one table to another (System.arrayCopy()).
  5. rehash() sets the internal count to new value, which is smaller, because many objects were garbage collected (soft references), lets say: count = 486 000
  6. The put() continues, disregards the count = 486 000 and sets the count to count = 786433
  7. Another element is inserted, however in this state, the count is still greater than threshold so the rehash happens again
  8. From now on every element added to map will trigger a rehash(), which has a huge performance impact.

When this happens in multithreaded environment, all the other threads are waiting (parked) for lock() until the rehash() and put() is done (and then the next one is doing the rehash() again). You can imagine what performance impact this is...

I don't understand how this bug could survive so many versions with nobody noticing despite the class is extensively used. Maybe I'm missing something ?

Proposed solution:

Update the c variable after rehash is done. Between lines 105 and 106 add:

c = count + 1

解决方案

The bug was reported on the Groovy JIRA https://issues.apache.org/jira/browse/GROOVY-7448 and is now fixed.

Fix Version/s:
2.4.4, 2.5.0-beta-1

这篇关于Groovy中的Bug AbstractConcurrentMap?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆