【问题标题】:Concurrency level for ConcurrentHashMap in synchronized method同步方法中 ConcurrentHashMap 的并发级别
【发布时间】:2017-01-14 20:32:44
【问题描述】:

我正在尝试解决内存泄漏问题。堆转储分析显示ConcurrentHashMap 正在占用98% of heap memory 周围。检查代码,发现ConcurrentHashMap 实例化使用的是没有参数的构造函数。 concurrencyLevel 的默认配置是 16。在此映射实例化之后,我看到一个同步方法调用,其中数据被放入映射中。

我想知道,由于数据只放在同步方法中,将ConcurrentHashMap 的 concurrencyLevel 设置为 1 是否安全?

以下是示例代码sn-p:

private volatile Map<String, Integer> storeCache;

public void someMethod() {
    storeCache = new ConcurrentHashMap<String, Integer>();
    syncMethod();
}

private synchronized void syncMethod() {
    storeCache.put("Test", 1);
}

【问题讨论】:

  • CHM 不使用任何字节数组,所以这不会有任何区别。默认 CHM 实例使用的空间至少比字节数组使用的 1 亿字节少 5 个数量级。
  • 我的观点:CHM 的内部空间并没有占据 98% 的空间,而是它所包含的东西。使用 1 的并行度将一无所获。
  • 您需要在应用程序代码中查找内存泄漏。有人在地图上添加了太多东西——就这么简单。您可以随时尝试将地图打印到文本文件中。
  • 参考这个链接后我问了这个问题 -- ria101.wordpress.com/2011/12/12/…
  • 关于 concurenthashmap 内存泄漏的一些优点在这里,在这个问题上:stackoverflow.com/questions/3959122/…

标签: java concurrency


【解决方案1】:

我想知道,由于数据只放在同步方法中,将 ConcurrentHashMap 的 concurrencyLevel 设置为 1 是否安全?

这当然是安全的,因为它不会导致任何地图损坏。但是,它不会修复您的内存泄漏。实际上,您可能不想同步对 ConcurrentHashMap 的访问,这已经保证了来自多个线程的安全读写。外部同步将单线程访问您的 CHM,这将消除 CHM 相对于 HashMap 的许多好处。如果删除synchronized 和specify a concurrencyLevel equal to the estimated number of concurrent writes,您可能会获得更好的性能。

至于您的内存泄漏,CHM 中的键和值是强引用,这意味着 Java 垃圾收集器不会收集它们,即使它们不再在您的代码中的其他任何地方引用。因此,如果您将 CHM 用作临时值的缓存,则当您的应用程序不再需要它们时,您需要 .remove() 它们。

(如果你想要一个没有强键的 ConcurrentMap 的语义,你不能开箱即用,但是Guava provides a pretty good alternative。)

您可能还想检查您在地图中 .put() 的键是否已正确实现 .equals() 和 .hashCode()。

【讨论】:

  • 确实有道理。感谢 Jason 撰写详尽的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-24
  • 2022-12-10
  • 1970-01-01
  • 2017-10-22
  • 1970-01-01
  • 2010-11-20
相关资源
最近更新 更多