从一个BUG说起
前段时间翻到了一个 JDK 有点意思的 BUG,带大家一起瞅瞅。
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8137185
memory leak,内存泄漏。
是谁导致的内存泄漏呢?
ConcurrentLinkedQueue,这个队列。
这个 BUG 里面说,在 jetty 项目里面也爆出了这个 BUG:
我看了一下,觉得 jetty 的这个写得挺有意思的。
我按照 jetty 的这个讲吧,反正都是同一个 JDK BUG 导致的。地址如下:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=477817
我用我八级半的蹩脚英语给大家翻译一下这个叫做 max 的同学说了些什么。
他说:在 Java 项目里面,错误地使用 ConcurrentLinkedQueue(文章后面用缩写 CLQ 代替)会导致内存泄漏的问题。
在 jetty 的 QueuedThreadPool 这个线程池里面,使用了 CLQ 这个队列,它会导致内存缓慢增长,最终引发内存泄漏。
虽然 QueuedThreadPool 仅仅使用了这个队列的 add 方法和 remove 方法。但不幸的是,remove 方法不会把队列的大小变小,只会使队列里面被删除的 node 为空。因此,该列表将增长到无穷大。
然后他给了一个附件,附件里面是一段程序,可以演示这个问题。
我们先不看他的程序,后面我们统一演示这个问题。
先给大家看一下 jetty 的 QueuedThreadPool 线程池。
看哪个版本的 jetty 呢?
可以看到这个 BUG 是在 2015 年 9 月 18 日被爆出来的。所以,我们找一个这个日期之前的版本就行。
于是我找了一个 2015 年 9 月 3 日发布的 maven 版本:
在这个版本里面的 QueuedThreadPool 是这样的:
可以看到,它确实使用了 CLQ 队列。
而从这个对象所有被调用的地方来看,jetty 只使用了这个队列的 size、add、remove(obj) 方法:
和前面 max 同学描述的一致。
然后这个 max 同学给了几张图片,来佐证他的论点:
主要关注我框起来的地方,就是说他展示了一张图片。可以从这图片中看出内存泄漏的问题,而这个图片的来源是他们真实的项目。
这个项目已经运行了大约两天,每五分钟就会有一个 web 请求过来。
下面是他给出的图片:
从他的这个图片中,我就只看出了 CLQ 的 node 很多。
但是他说了,他这个项目请求量并不大,用的 jetty 框架也不应该创建这么多的 node 出来。
好了,我们前面分析了 max 同学说的这个问题,接下来就是大佬出场,来解惑了:
我们先不看回答,先看看回答问题的人是谁。
Greg Wilkins,何许人也?
我找到了他的领英地址:
https://www.linkedin.com/in/gregwilkins/?originalSubdomain=au