我们最近花了很多时间跟踪弹性云服务中的各种内存问题。特别是其中一个攻击活动相对较少的小集群,需要进行大量挖掘才能找到答案。
每个节点都有一个固定的内存量,我们为堆保留了大约一半的内存。其余的由JVM和文件缓存使用。通常,JVM使用的内存是恒定的,但是我们看到一些实例,Elasticsearch使用的总内存不断无限制地缓慢增加,直到达到总限制。有时需要几天时间,但它一直在不断攀升。当达到限制时,节点将耗尽内存并重新启动。
所以这是内存泄漏的一个非常明显的迹象。我们使用Yourkit、MAT等工具分析了Elasticsearch,但在堆中找不到任何可以解释这一点的东西,但是Elasticsearch进程的RSS(resident set size)内存在不断增加。我们尝试打开本机内存跟踪,发现内存增加根本不在堆中。
本机内存跟踪(NMT)是JVM中的一个特性,它提供了一种查看JVM内部内存使用情况的方法。它跟踪所有内存分配,并按使用情况对其进行分组。这既提供了内存去向的概述,也提供了分配发生的详细信息。
NMT的报告如下:
然而,即使使用NMT对Elasticsearch过程进行了长时间的分析,操作系统测量的内存使用量的增长速度比NMT报告的要快得多。这表明内存泄漏超出了JVM的跟踪能力。我们有本机内存泄漏!
输入跟踪本机内存分配的工具。幸运的是,有人描述了用jemalloc实现这一点的一种方法。
以下是我使用Elasticsearch运行它的步骤:
git clone http://github.com/jemalloc/jemalloc
cd jemalloc ./autoconf.sh --enable-perf
make dist
make
sudo make install
然后我在启动Elasticsearch之前添加了这些env变量:
export LD_PRELOAD=/usr/local/lib/libjemalloc.so
export MALLOC_CONF=prof:true,lg_prof_interval:30,lg_prof_sample:17,prof_final:true
我用X-Pack运行了5.1.1版的Elasticsearch,它显示了内存泄漏,我还启用了X-Pack监视功能,只是为了让一些轻量级的索引能够正常运行。然后我运行了一夜,因为我们已经看到这个泄漏在缓慢发生。
随后,生成以下输出:
jeprof --show_bytes --gif /usr/lib/jvm/java-8-oracle/jre/bin/java jeprof*.heap > /tmp/app-profiling.gif
输出如下所示(滚动到底部):
在底部,JVM实际上只引用了80%的内存,因此我们“损失”了20%。这是在运行了24小时之后。当我开始这个过程的时候,这个比例是97%,所以损失一直在增加。
在详细信息中,您可以看到哪个方法分配了内存。最大的罪魁祸首似乎是java.util.zip.Inflater和java.util.zip.Deflater占“丢失”内存的18.2%。
Inflater和Deflater是使用本机函数实现的,本机函数为缓冲区分配内存。如果您忘记对它们调用end()
,则内存永远不会被释放。但是,它实现了一个终结器,如果您忘记了,它应该为您运行end()
。但终结器只在完全垃圾回收full gc时调用,并且当所有引用都不存在时。使用较少的集群几乎永远不会完成完整的Full GC,因此在实践中它们从未被清理干净。
我们使用Yourkit查看了Inflater
和Deflater
的使用方法,发现了一些可能忘记关闭它们的地方:
并非所有这些都是真正的泄漏,它们可能仍在使用,但我们对它们进行了调查。这项调查导致了Lucene和Elasticsearch中的各种修复:
http://issues.apache.org/jira/browse/LUCENE-7647
http://github.com/elastic/elasticsearch/pull/22711
为了验证我们是否捕捉到了所有的情况,我们制作了一个小工具来记录我们分配Inflater
的时间以及对它调用end()
的时间。它是作为一个代理实现的,它对Inflater
类进行检测。我们在Elasticsearch 5.1.1上运行了这个工具,它准确地显示了需要修复的地方,而在5.2.1中,它没有显示任何地方(除了一些由于jar缓存而预期的地方)。
我们已经看到,当普通的内存评测工具无法识别内存问题时,它可能在JVM之外。在这种情况下,我们需要窥视它的内部。由于JVM只是一个“普通”的C++程序,所以我们可以使用众所周知的工具和技术来分析它。
除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/1164.html
暂无评论