LOADING

加载过慢请开启缓存 浏览器默认开启

guava的Cache内存泄漏风险

环境描述

  • Linux服务器:Centos7.6 4核8G

  • guave版本

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>27.1.jre</version>
    </dependency>
    
  • JDK版本:1.8

问题的发现

在进行接口测试时,发现频繁请求接口会导致服务器的CPU居高不下,Java的GC无明显日志信息(可能抢占不到CPU,日志输出不了),通过jmap获取堆栈信息,然后使用ha457.jar查看,如下图:

发现com.google.common.cache.LocalCache$Segment占了大量内存,GC无法清理,导致频繁GC然后CPU升高。仔细观察是java.util.concurrent.ConcurrentlinkedQueue$Node引起的。然后去百度了下,看到这个类存在内存泄漏的风险(文章地址),但是这个文章说的是remove方法,观看了google的cache源码发现ConcurrentlinkedQueue的实列只调用了add(),poll(),offer()方法。百思不得其解,就去了GitHub,看到了关于Guava LocalCache recencyQueue is 223M entires dominating 5.3GB of heap的文章。

最后的解决方案

人家都说了用Caffeine,就乖乖用吧。

疑点

In synthetic tests this is easy to reproduce, but was viewed as not viable in realistic usages to handle beyond a safety threshold (per CLHM in your reference). The long-term was to switch to a ring buffer, but that kept being put off as not seen as overly critical. Without a real-world error, it was seen as a GC + perf optimization which is less important given Google’s impressive infrastructure (e.g. less application cache centric by having fast data stores).

为什么综合测试中很容易复现,但实际中是不可行的?