同事用java开发了一个系统,其中有一个功能是下载大约10万笔数据到Excel中。当上线后,很多用户反映下载数据量大的时候就不能成功,但有时可以,所以结论就是系统不稳定,这个问题拖了很久没有解决。
在与这个系统的开发人员看了下代码后,知道下载excel用的是apache中的POI组件。原来的代码逻辑是将要下载的数据整个从数据库捞出来,然后循环一笔笔地调用POI的API生成cell, row,全部完成了,再输出到客户端的流中。监控发现,一旦下载时,java虚机所占用的内存直线上升,且很久都不会降下来。
所以判定为大数据保存在内存中,再生成excel对象这一过程占用了大量内存,当多个人并发这一功能时,服务器的内存hao尽,就不能成功。我这个同事一直觉得java的处动清理机制应该可以释放,所以他总觉得是tomcat中有什么配置不正确。但是java的释放大对象的时候速度是很慢的。这与.net一样。所以关健的问题是不用在内存中生成这种占用内存大的对象,否则并发多的时候,java回收内存是很慢的。
知道了根本原因,就要从POI中入手,看是否能让POI在生成excel的时候,持久化到本地硬盘中,这样内存可以限制在很小范围内,比如10M,一旦满了,就写入硬盘。这一想法果然在POI3.7中找到了。但3.7以前都没有提供。这个类叫SXSFWorkbook在poi-ooxml-3.7-20101029.jar, 完整域名是org.apache.poi.xssf.streaming.SXSFWorkbook