首页 > 教程攻略 > ai教程 >【Itext】解决Itext5大并发大数据量下输出PDF发生内存溢出outofmemery异常

【Itext】解决Itext5大并发大数据量下输出PDF发生内存溢出outofmemery异常

来源:互联网 时间:2026-08-18 20:34:13

尼玛,这个问题干扰了我两个星期!!

关键字 itext5 outofmemery 内存溢出 大数据 高并发 多线程 pdf 导出 报表 itext 并发

在读<4.3节(Dealing with large tables)的时候,书上写道:itext5PdfPTable实现了ILargElement的接口,只需要我们手动设置datatable.setComplete(false);之后,它就可以自动将表格元素输出到document中,但是,对,就是这个但是!!我们的cell之多,多到它来不及去放进去,比如我并发100个线程去访问它,别说tomcat受不了,was也照样挂掉,给他8个G,它也照样吃掉,而且服务卡死。你说这样的产品放出去,我放心不?

于是,我大量Google,大量百度,大量Csdn,大量Ja vaEye,多少次的说多了都是泪,最后,yes,就是最后,我Tm什么法子都想了,list清空,指针赋null,优化程序循环,优化bufferedOutPutStream输出,优化下载,就差给Itext作者写信了!!现在解决了这个高并发的问题,可以边生成边输出到IO磁盘,防止以前高并发,大家发生死锁,围着内存和IO卡死

然后无名小卒兄居然也碰到了这个问题,而且这个博客我都不知道自己是怎么搜到的。他在处理中用到了一个自己写的方法:根据行号来控制执行次数。比如可以定义为

每 1000 行释放一次 table

,先把 table 放到 document 中,因为这时 document 里已经能查到你的 table 了,再通过

datatable.setComplete(false)

方法,让它开始持续往文件里搬运数据。等这一批数据写入完成之后,再把这些已经放进去的元素删掉,也就是使用

table.deleteBodyRows();

。这样一来,问题确实缓解了,不过又会引出一个新的情况:每隔 1000 行就会重新生成一个表头。于是无名兄又加上了

table.setSkipFirstHeader(true);

,到这里,前面的几个问题基本就都解决了。

 int _MAX_ROWS = 1000;//最大行数,之后清理 int row_count = 0;//初始值 if (  row_count % _MAX_ROWS == 0) {System.out.println("row_count % _MAX_ROWS="  row_count % _MAX_ROWS);// add table to Document document.add(datatable); // delete _MAX_ROWS from table to free memory datatable.deleteBodyRows();// let iText manage when table header written //datatable.setSkipFirstHeader(true);
}

或者

int fregmentSize = 1000;// 释放内存的行号int k = 0;for (int i = 0, h = bodys.size(); i < h; i  ) { if (i != 0 && i % fregmentSize == fregmentSize - 1) {System.out.println("第[ "   (i   1)   " ]行进行内存释放 "   ((k  )   1)   " th");document.add(datatable);datatable.deleteBodyRows();datatable.setSkipFirstHeader(true);} //.... 表格处理}

经过我的实际调试,我发现一个比较容易踩坑的问题:如果前一页最下方的剩余空间已经放不下某一整行数据,写入时就必须换到下一页;这种情况下如果你强制使用splitRow(false)来禁止拆分行,

就很可能出现数据丢失

。所以更建议不要刻意禁止表格拆分。当然,如果你确实担心内存问题,也可以把清理表格的阈值适当调大一些,比如到1000行再清理,而不是100行就清一次,不然表格还没攒够,内存压力反而更明显。像下面这种方式就是我更推荐的做法:允许它在上一页放一部分、下一页接着放一部分即可。其实这种极限场景并不常见。比如下面这个demo,就是我在100个线程并发访问、生成5800行*33列数据时做出来的一个比较特殊的pdf,前一页留一点、后一页接一点,打印出来反而更美观,没必要为了整行不拆分,硬让前一页留下大块空白。

1.清理缓存并换页,第200行数据跑到了下一页,199行之后留了空白出来。(此种不推荐)

\

2.清理缓存不换页(推荐此种)事实证明,当你把fregmentSize的值上升到1000行一清理,就不会出现换页的问题。大家量力而行把。

\

落雨(感谢无名兄给的很好的思路!!先添加了再删掉再添加。good)

394263788

2013年9月11日 10:04:12