poi导致内存泄露分析

背景

最近线上的机器偶尔会出现cpu打满的情况,内存也很吃紧,导致影响系统的正常运行。如下:

ios 内存泄漏三方库 poi 内存泄露_内存泄露


ios 内存泄漏三方库 poi 内存泄露_内存泄露分析_02


ios 内存泄漏三方库 poi 内存泄露_poi内存泄露_03


ios 内存泄漏三方库 poi 内存泄露_上传_04

可以看出,已经严重影响到线上程序的运行了。

分析

用jmap打出对应的dump文件并用MAT工具打开。

ios 内存泄漏三方库 poi 内存泄露_poi内存泄露_05


很明显发生了内存泄露。

观察一下支配树。

ios 内存泄漏三方库 poi 内存泄露_ios 内存泄漏三方库_06


可以看出,占用内存最多的是char[]数组对象,总共有700+万个。其次是XSSFSheet,共应用了300+mb的对象。

我们再看看当时的线程栈是怎样的。

ios 内存泄漏三方库 poi 内存泄露_ios 内存泄漏三方库_07


频繁出现poi的相关类很明显有问题。

查看代码,这是解析上传的excel相关的代码。

是不是上上传的excel大小太大了呢?

ios 内存泄漏三方库 poi 内存泄露_内存泄露_08


看一看出poi内部是用treemap存储列和行信息的。

我们分别打印一下行数和列数

ios 内存泄漏三方库 poi 内存泄露_内存泄露分析_09


ios 内存泄漏三方库 poi 内存泄露_内存泄露_10


发现这是一个有234行和16384列组成的excel,按照预期,我们要求上传的excel只需要有一列就可以了。除此之外,表面上看excel也不是很大啊。

我们尝试创建一个这样的excel,并上传。

ios 内存泄漏三方库 poi 内存泄露_上传_11


问题复现了

我们来看看excel有多大,只有15mb,15mb却用了2Gb左右的内存来解析,经过排查,排除了代码的问题。那么可能出错的就只有poi本身了。

经过调查,poi分为用户模式和sax模式来解析excel,用户模式适合处理小数据量的excel,sax适合用来存储数据量的excel,而项目中用的是用户模式,改变为sax模式或者限制上传的excel大小即可解决。

具体poi的相关知识这里不再细说。