做excel导出,数据很多,列也很多。估计现在行*列的值在140万,以后会更加的多。由于项目要求,必须全部导出表中的数据。但我用jxl发现,当数据多时,会报OutOfMemory的错误。我做过一个test测试,jxl处理500000没有问题,但处理1000000就会出现OutOfMemory错误了。
可以肯定是jxl的问题,但我不明白怎么jxl没有对象释放的方法呢???
测试代码:
jxl.write.WritableWorkbook wwb = null;
jxl.write.Label labelC = null;try {
wwb = Workbook.createWorkbook(new File("c:\\1.xls"));
for(int i=0;i<50000;i++) {
wwb = Workbook.createWorkbook(os);
for(int j=0;j<100;j++) {
labelC = new jxl.write.Label(j, i, "This is a Label cell1");
}
}
wwb.write();}
catch (Exception e)
  {
    System.out.println(e);
  }
  finally {
    try {
      os.close();
      wwb.close();
    }
  catch(Exception e) {
    System.out.println(e);
  }
}

解决方案 »

  1.   

    最大限度的共用对象,如果不需要时及时置为null,
    最好不要在for循环中用new运算符,尽量用赋值进行替代
    将for(int j=0;j<100;j++)改为 for(int j=0;j<100;++j) 或 由递增改为递减
    在操作N次后或是隔N久后进行一下System.gc() [n自定,视内存测试结果而定]
      

  2.   

    我在标头声明jxl.write.Label labelC = null;在循环中调用,对象就只有1个,我觉得问题出在
    labelC = new jxl.write.Label(j, i, "This is a Label cell1");
    ws.addCell(labelC); --问题的原因,加入的对象太多
    但好像jxl没有提供ws.clear()释放对象的函数哦
      

  3.   

    一直在生成新的Label对象,却没有发现明确将不用的对象标出。
    labelC = null;有利于系统及时有效地回收垃圾。适当调用System.gc()也是很有效的。
      

  4.   


    wwb = Workbook.createWorkbook(os);//这句生成的是什么
    wwb = Workbook.createWorkbook(new File("c:\\1.xls"));//这句生成的是什么
      

  5.   

    不管用。仍然还是报内存溢出的错误。
    jxl.write.WritableWorkbook wwb = null;
    jxl.write.Label labelC = null;
    jxl.write.WritableSheet ws = null;
    int iCount = 0;
    try {
    wwb = Workbook.createWorkbook(new File("c:\\1.xls"));
    ws = wwb.createSheet("Test Sheet 1", 0);
    for(int i=0;i<50000;i++) {
    if(iCount>5000) {
    iCount=0;
    labelC = null;
    System.gc();
    }
    for(int j=0;j<100;j++) {
    labelC = new jxl.write.Label(j, i, "This is a Label cell1");
    ws.addCell(labelC);
    }iCount++;}
    wwb.write();
    }
    catch (Exception e)
      {
        System.out.println(e);
      }
      finally {
        try {
          wwb.close();
        }
      catch(Exception e) {
        System.out.println(e);
      }
    }
      

  6.   

    不关GC的问题。
    ws.addCell(labelC); 只符labelC = null,其实ws对象根本还没有清空。
      

  7.   

    if(iCount>5000) {
    iCount=0;
    labelC = null;
    System.gc();
    }
    ----------------------------
    我倒……
    把labelC = null;放在这里,有意义???
      

  8.   

    看看WritableWorkbook及其它的对象有没有flush方法,有的话就在相应位置调用,也就是要将数据及时输出到文件中,不能一直放在内存中。
      

  9.   

    //楼上说滴对,最好能及时写入文件,老占着内存,早晚肯定会出问题滴
    //下面滴可能只会起部分作用,恐怕不会从根本上改变局面,必竟内存是有限滴for(int i=0;i<50000;++i) 
    {
        if(iCount>5000)//根据内存测试结果进行调整为宜
        {
            iCount=0;
            System.gc();
        }
        
        for(int j=0;j<100;++j) 
        {
            ws.addCell(new jxl.write.Label(j, i, "This is a Label cell1"));
            //也可用下面滴,不知效果会如何
            //labelC = null;
            //labelC = new jxl.write.Label(j, i, "This is a Label cell1");
        //ws.addCell(labelC);
        }
        
        iCount += 1;
    }
      

  10.   

    不知这样如何:
    for(int i=0;i<50000;++i) 
    {
        for(int j=0;j<100;++j) 
        {
            ws.addCell(new jxl.write.Label(j, i, "This is a Label cell1"));
            //也可用下面滴,不知效果会如何
            //labelC = null;
            //labelC = new jxl.write.Label(j, i, "This is a Label cell1");
        //ws.addCell(labelC);
        }
        System.gc();
    }
      

  11.   

    如果程序执行到 wwb.write(); 才真正写文件
    labelC只不过是依次指向各个jxl Label的句柄而已
    将它置null或者主动调用gc()过程都是徒劳的在没有执行wwb.write()之前有没有生成文件?
      

  12.   

    呵呵,是你的内存不够用了啊,这么搞的话迟早会outofmemory的。一个方法是加大你的jvm内存设置,还有就是你找找,看看jxl有没有分批写入的功能,实际上jxl一次写入的方法是对的,这样才可以达到高效,但缺点就是容易把你的内存吃光。你找找看,如果能分批,比如每10000条写一次到文件,这就好处理了。我想应该可以实现吧?你每10000条写一次,同时记住当前的行数,然后下次从这行开始写就是了,应该可以达到你的要求。
      

  13.   

    好热闹的回复,放弃了jxl,用的csv分次写入,虽然慢,不过内存控制在10M内,问题已经解决了,谢谢大家。
    个人认为,jxl对于大数据量的导入导出还是存在缺点的,支持5M的数据一次导入导出,但因为jxl提供的write()只能提交一次,而开大内存,个人认为确实可以解决问题,但显然不佳,我导100多万条数据出来,既然要150M的内存,如果用排版函数,内存更多。有时间研究一下它的代码。