zoukankan      html  css  js  c++  java
  • 【Itext】解决Itext5大并发大数据量下输出PDF发生内存溢出outofmemery异常

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

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

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

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

    然后无名小卒兄居然也遇到了这个问题,而且这个博客我都不知道怎么搜到的,他中间用到了自己写的一个方法,根据行号去定次数,比如定义1000行一次释放table,将table先放到document,正好document中查到了你的table用datatable.setComplete(false)方法,于是它就开始往文件里面搬运数据,之后,我们删掉这些已经放进去的元素,用table.deleteBodyRows();好,这样产生了一个新的问题,就是每隔1000行,产生一个表头,于是无名兄又用到了table.setSkipFirstHeader(true);ok至此,解决全部问题,但是后续问题,无名兄遇到了,万一某一行刚刚好是最后一页,那么后续的表格没有了表头,这个问题我没遇到,因为我用到了另一个方法,就是  datatable.setHeaderRows(headerRows);// 设置头几行为表头(已经判断好了前几行为表头),这样我们就搞定了这个itext内存溢出的大问题!!也许很多人都不会遇到这个错误,但是我保证这个内存溢出会让你恨死Itext,现在好了,有了这个解决方案,就是几千万人并发又如何?代码稍后贴出。

     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

  • 相关阅读:
    初识RabbitMQ
    ThreadPoolExecutor中execute和submit的区别
    MYSQL bin_log 开启及数据恢复
    MYSQL 悲观锁和乐观锁简单介绍及实现
    linux php多版本
    easyui汉化啊!
    虚化技术的额外开销
    拍脑袋空想不可能有创新
    大规模WEB服务技术
    xunsearch bsd 10.1安装心酸路。。。
  • 原文地址:https://www.cnblogs.com/ae6623/p/4416430.html
Copyright © 2011-2022 走看看