4

java直接内存

 3 years ago
source link: http://javakk.com/1172.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
[收起] 文章目录
  • java堆外内存泄漏排查案例

java堆外内存泄漏排查案例

我在Twitter的团队意外地建立了一个系统来检测激动人心的体育赛事:我们在三个不同的场合被寻呼,因为我们的一个服务在一个数据中心宕机。不用说,我们希望尽快取消这个系统的建设。我第一次被传呼是在西雅图海鹰队NFL季后赛的比赛中,在最后一分钟打成平手。我想其他的网页是由于NCAA篮球和板球世界杯。

这些事件导致大量用户同时发微博,发送流量大幅飙升。我们的服务最终使用了几GB的额外内存,并被Linux内核杀死。在一个实例被杀死后,其余实例的负载会增加,最终会将它们全部关闭。作为一个JVM服务,“额外”内存必须是native memory本机内存,而不仅仅是普通的Java对象分配,但是我们的服务没有对本机内存做任何特殊的处理。几周前,我们终于发现了潜在的Java本机内存泄漏。

始终关闭 gziputstreamgziputstream ,因为它们通过 zlib 使用本机内存。要追踪泄漏,请使用Jemalloc,并使用 MALLOC_CONF 环境变量启用采样分析。

与我之前提到的JVM mmap垃圾收集暂停类似,很多人花了很多时间调试这个问题,历时数月。每次我们被传呼时,我们都会设置额外的解决方法,以使将来更难触发。我们也花了更多的时间试图找到“真正的”错误,没有太多的成功。这个特殊的问题很容易重现:只需向一个测试实例发送许多并发请求。不幸的是,减慢实例的速度(例如使用strace)会使问题消失。既然我们的缓解措施似乎奏效了,我们就转向了更优先的问题。

几周前,有人报告了一个与我们类似的问题。kirandeeppaul建议使用jemalloc的内置分配配置文件,它跟踪调用malloc的内容。这是相对较低的成本,因为它只对malloc调用的一小部分进行采样。这也很容易尝试,因为可以通过设置MALLOC_CONF环境变量来打开它,而无需任何代码更改。这就成功了。

我的设置:

MALLOC_CONF=prof:true,lg_prof_interval:30,lg_prof_sample:17

它在每分配1 GB之后将配置文件写入磁盘,并每128 kB记录一次堆栈跟踪。可以使用jeprof(jemalloc的一部分)将此文件转换为图形。这为我们的服务创建了下图。

ayE7Rjb.png!mobile

这表明 94% 的“活动”块是由Java_Java_util_zip_deflatter_init和deflatInit2(zlib的一部分)分配的,而只有4%来自os::malloc和JVM本身。

我发现这个程序压缩任何东西都很奇怪,所以我向Carsten Varming(Twitter-NYC的本地JVM专家)提到了它。他以前在Twitter上见过Deflater导致内存问题。它使用本机zlib库,该库使用malloc分配一个小缓冲区。如果它没有关闭,那么直到终结器运行时内存才会被释放,这可以解释这些症状。

我们使用linux perf来查找压缩内容的代码。在Twitter上,我们将JVM和perf配置为跨本机代码和Java代码生成堆栈跟踪,因此我运行perf record-g-p(PID)来记录堆栈跟踪,同时生成重载(您可以使用perf map agent来实现这一点)。

然后,我使用perf report搜索引用Deflater的堆栈,这很快就显示了 罪魁祸首 :一个异常记录器在压缩消息时没有关闭GZIPOutputStream。这解释了为什么它只发生在重载期间:只有在垃圾收集之间发生大量异常时,内存使用才会增加,最终终结器将运行以清除本机分配。添加 try/finally 块来关闭流解决了这个问题,并在负载下稳定了服务的内存使用。

我花了几个小时在Twitter上审核GZIP流的所有用法,发现有几个地方忘记关闭流。我不认为它们中的任何一个会导致类似的内存泄漏,但我还是修复了它们,以避免将来的复制和粘贴错误。(我在Apache Spark中也发现了一个)我认为FindBugs会报告这些问题的警告,这显示了静态分析的潜在价值,特别是对于这种“已知危险”的情况。我希望有一个预提交检查器阻止人们提交没有调用close()的代码使用。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK