ConcurrentHashMap$Node 累积在堆中而没有被 GC 清理

问题描述 投票:0回答:2

我正在使用

ConcurrentHashMap
来缓存一些短期数据。即缓存中的条目不多,但经常发生插入和删除。问题是,当在负载下工作时,GC 不会删除
java.util.concurrent.ConcurrentHashMap$Node
并且它们会累积在堆中。即使负载结束后,它们也没有被清理。

我的单例缓存管理器

@Component
public class ZipkinTraceCacheManager {

    private final Map<String, ZipkinTraceCache> threadCaches = new ConcurrentHashMap<>();

    public ZipkinTraceCache getCache(String mainSpanId) {
        return threadCaches.get(mainSpanId);
    }

    public void removeCache(String mainSpanId) {
        threadCaches.remove(mainSpanId);
    }

    public String initNewCache(Span mainSpan) {

        ZipkinTraceCache zipkinTraceCache = new ZipkinTraceCache();
        zipkinTraceCache.setMainSpan(mainSpan);

        String mainSpanId = mainSpan.context().spanId();

        threadCaches.put(mainSpanId, zipkinTraceCache);

        return mainSpanId;
    }
}

如图所示,已用堆的最小值正在增长 memory usage

负载结束后,所有

java.util.concurrent.ConcurrentHashMap$Node
实例仍处于活动状态 heapdump

我需要做什么才能停止积累这些参考文献?

java hashmap garbage-collection heap-memory
2个回答
0
投票

你使用的是Spring还是spring-boot? @Component 具有单例的默认范围,这意味着:-

当 Spring IoC 容器启动时,它会创建一个单例 bean 的实例,并且该实例在应用程序上下文的整个生命周期内都存在。因此,任何类变量(例如示例中的 threadCache)也会被实例化,并在应用程序上下文的整个生命周期内有效。当包含 threadCache 的单例 bean 符合垃圾回收条件时,将发生 threadCache 的垃圾回收。当应用程序上下文关闭或整个应用程序关闭,并且没有其他对单例 bean 的引用时,通常会发生这种情况。


-3
投票

ConcurrentHashMap.Node 在堆中累积而没有被垃圾收集器 (GC) 清理可能是由于一些潜在原因造成的,通常与引用或内存保留有关。以下是一些常见场景以及调查并可能解决问题的步骤:

  1. 无法访问的引用:检查是否存在对 ConcurrentHashMap.Node 实例的强引用,从而阻止它们被垃圾收集。如果对象的保留时间超过必要的时间(例如,通过缓存或长期存在的数据结构),就会发生这种情况。 解决方案:检查您的代码,确保对 ConcurrentHashMap.Node 实例的引用在不再需要时得到适当释放。如有必要,请使用弱引用或其他内存管理技术。
  2. 并发问题:如果存在与并发访问和修改数据结构相关的错误,像 ConcurrentHashMap 这样的并发数据结构有时会导致意外的内存保留。 解决方案:检查您对 ConcurrentHashMap 的使用情况,以确保所有操作(插入、删除等)在并发环境中正确且安全地执行。检查是否有任何潜在的竞争条件或线程安全问题。
  3. 内存泄漏:如果 ConcurrentHashMap.Node 实例随着时间的推移而累积并且没有被垃圾回收,则可能表明存在内存泄漏。这可能是由于不正确的使用模式导致对象无意中保留在内存中。 解决方案:使用内存分析工具(例如 Java Flight Recorder、VisualVM 或 YourKit)来分析堆转储并确定应用程序的哪些部分保留了 ConcurrentHashMap.Node 实例。查找可能导致泄漏的任何可疑模式或参考。
  4. JVM 设置和垃圾收集调整:有时,不正确的 JVM 设置或垃圾收集调整可能会导致内存保留问题。例如,如果堆大小太小或垃圾收集未最佳配置,则可能无法有效收集对象。 解决方案:检查您的 JVM 设置(例如,堆大小、垃圾收集器算法),以确保它们适合您的应用程序的内存使用模式。尝试不同的设置以找到最佳配置。
  5. 代码审查和分析:执行全面的代码审查并使用分析工具来识别代码中潜在的改进领域。查找任何可能导致内存保留的不必要的对象分配或低效的数据结构。
  6. 升级库和 JDK:确保您使用最新版本的 JDK 和任何相关库(包括 ConcurrentHashMap 实现)。有时,新版本的软件中包含内存管理改进和错误修复。 总之,调查 ConcurrentHashMap.Node 在堆中的积累需要对应用程序的代码、并发模式、内存管理实践和 JVM 设置进行彻底分析。通过识别并解决问题的根本原因,您可以优化内存使用并防止不必要的堆积累。
© www.soinside.com 2019 - 2024. All rights reserved.