我正在研究我最近的一个项目中的内存问题,该项目将数据保留在内存中以进行快速访问,但是应用程序的内存占用量非常大。

该应用程序大量使用CHM(即Concurrenthashmap) ,因此,无需再费脑筋地猜测CHM是问题所在。 我进行了一个内存分析会话,以了解CHM实际占用了多少内存。

我对结果感到惊讶,CHM占用了大约50%的内存。 因此,可以确定CHM是问题所在,它速度很快,但内存效率不高。

为什么CHM这么胖?

  • 键/值由Map.Entry对象包装,这为每个对象创建了一个额外的对象。
  • 每个段都是一个可重入锁,因此,如果您有很多小的CHM且默认为并发级别,则将有很多锁对象,并且该对象将排在首位。
  • 还有更多的州开展家政活动。

上述所有对象都对内存消耗做出了很好的贡献。

我们如何减少内存占用

如果很难减少CHM的内存占用量,我想到的一些可能原因是

  • 它必须支持Map的旧界面
  • Java映射使用的哈希码冲突技术是封闭哈希 封闭式散列基于在冲突时创建链接列表,封闭式散列对于解决问题非常快,但它对CPU缓存不友好,尤其是当节点进入较大的链接列表时。 关于LinkList问题有一篇有趣的文章

因此,我们需要一种内存效率高的替代CHM实现。

CHM版本2

我开始创建具有低内存占用量的CHM版本,目标是尽可能接近数组。 我还使用了替代的哈希码冲突技术来检查性能, Open_addressing有很多选项

我尝试了以下选项:

  • 线性探测 –性能并不是那么好,尽管这是最友好的CPU缓存。 需要花费更多的时间来解决问题。
  • Double_hashing –性能在可接受的范围内。

让我们测量CHM V2

  • 内存占用

试验ConcurrentHashmap

在内存方面有很大的收获,CHM比原始数据多花了大约45%+,新实现的LCHM非常类似于Array类型。

  • 单线程PUT性能

试验ConcurrentHashmap

CHM在PUT测试中的表现胜过新产品,对于100万个项目,新实施的速度要慢50到80毫秒。 50到80 ms并不是明显的延迟,我认为这对延迟要求以秒为单位的应用程序来说是很好的。 如果延迟要求以毫秒/纳秒为单位,则CHM的任何方式都不是一个好的选择。 LCHM性能较慢的原因是哈希冲突技术,双哈希用于解决有代码冲突的问题。

  • 并发添加性能

试验ConcurrentHashmap

当使用多个线程来写入映射时,新实现的性能稍好。

  • 取得成效

试验ConcurrentHashmap

与CHM相比,GET的性能略慢。

结论

新的实现在内存测试中表现出色,并且在获取/输出测试中有点慢。 有几件事情可以做,以提高获取/输出的性能,我们看到的所有性能差异都归因于所使用的探测技术。

  • 可以改进探测技术,可以使用线性探测技术来获取缓存友好的访问。
  • 使探测技术并行化非常容易。

参考:Are Are ready博客上试验我们JCG合作伙伴 Ashkrit Sharma的ConcurrentHashmap

翻译自: https://www.javacodegeeks.com/2013/05/experiment-with-concurrenthashmap.html

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-05-06
  • 2022-01-24
  • 2021-11-04
  • 2021-07-26
  • 2021-12-14
猜你喜欢
  • 2021-11-03
  • 2021-06-20
  • 2022-03-07
  • 2021-10-07
  • 2022-12-23
  • 2021-08-28
  • 2021-04-18
相关资源
相似解决方案