`
frank1998819
  • 浏览: 758599 次
  • 性别: Icon_minigender_1
  • 来自: 南京
文章分类
社区版块
存档分类

大量数据生成excel时候造成jvm内存泄漏问题的解决与测 (转)

    博客分类:
  • Java
 
阅读更多
一、从数据库中取大量数据(10万行左右)的时候,用jxl工具写excel,由于jxl是将每一个单元格生都成一个Cell对象,每一个对象都要消耗一定的内存空间,所以很容易导致内存溢出:

sheet0.addCell(new Label(colnum++,rownum,rs.getString("aname"),stuformat))//

tomcat报异常为:

java.lang.OutOfMemoryError: Java heap space

虽然在数据量在1—2万行左右的情况下,不会报异常,但是对服务器的资源消耗也是比较大的。

二、解决方法



要从消耗内存的原因出发解决,既然是由于生成大量的对象导致,就避免java创建太多的对象,就不能用jxl了。

另外可以对提前的数据进行情况来提取,对于不需要的数据可以不提取,节省时间和资源消耗。

用数据流的方法解决:

(1)直接写.txt文本文件,用”/t”来分割内容,可以从txt中直接复制到excel文件中。

public static void main(String[] args) {

       try {

           FileOutputStream fos = new FileOutputStream("hellotxt.txt");

           OutputStreamWriter osw=new OutputStreamWriter(fos);

           osw.write("aaa,bbb,ccc,ddd,eee,fff/r/n");

           osw.write("aaa/tbbb/tccc/tddd/teee/tfff/r/n");

           osw.flush();

           osw.close();

       } catch (IOException e) {

           e.printStackTrace();

       }

}

记事本打开效果如下:

aaa,bbb,ccc,ddd,eee,fff

aaa bbb ccc ddd eee fff

直接从记事本负责粘贴到excel中,效果如下:




aaa,bbb,ccc,ddd,eee,fff



















aaa


bbb


ccc


ddd


eee


fff




(2)也可以写成.csv

.csv文件打开格式跟excel基本一样,但是写入方式和写文本方式类似,可以以流的形式追加,只要在每列之间以固定标识符进行间隔,不存在内存和格式问题.

public static void main(String[] args) {

       try {

           FileWriter fw = new FileWriter("helloCsv.csv");

           fw.write("aaa,bbb,ccc,ddd,eee,fff,ggg,hhh/r/n");

           fw.write("aa1,bb1,cc1,dd1,ee1,ff1,gg1,hh1/r/n");

           fw.write("aaa/r/n");

           fw.write("aa2,bb2,cc2,dd2,ee2,ff2,gg2,hh2/r/n");

           fw.close();

       } catch (IOException e) {

           e.printStackTrace();

       }

    }



用excel打开文件显示如下,可以看到英文的逗号被作为了分割符而不显示出来。




aaa


bbb


ccc


ddd


eee


fff


ggg


hhh




aa1


bb1


cc1


dd1


ee1


ff1


gg1


hh1




aaa

























aa2


bb2


cc2


dd2


ee2


ff2


gg2


hh2


用记事本打开显示如下,逗号被作为内容的一部分显示出来:

aaa,bbb,ccc,ddd,eee,fff,ggg,hhh

aa1,bb1,cc1,dd1,ee1,ff1,gg1,hh1

aaa

aa2,bb2,cc2,dd2,ee2,ff2,gg2,hh2



注:写.csv文件的时候要注意里面的英文逗号,在用excel打开.csv文件的时候,英文逗号作为单元格之间的分隔符不显示出来。所以写的内容中的英文逗号要替换掉。



(3)写html

HTML   和   Excel之间通过改后缀名是可以相互转换的,  所以,可以先写HTML,这样内存不会溢出,写好后再改成xls后缀名。  

打开一个EXCEL,然后,选择另存为网页,可以看一下这个HTML的源码,直接把这个HTML文件后缀名改为xls,打开后效果和刚才那个EXCEL一样,但是会文件会变大。但是,压缩后比EXCEL还小。



以上几种方法以写.txt文件操作简单,效率比较高,写.csv文件效率跟写txt文件查不多,而且在小于65535行的情况下可以直接用excel打开,如果采用这个方法并且想用excel直接打开,行数如果多于65535行需要写多个.csv文件,并且要注意替换掉内容中的英文逗号,写html文件要写大量的标签,相对txt和csv文件内容会增加很多,具体写法可以上网查。比较优劣效率易编写情况,综合得出可以采用写txt和csv方法。





在网上查询相关资料,结合本案例,做的一个测试:

在java写文件中,通常会使用FileOutputStream和FileWriter,FileWriter只能写文本文件。 FileOutputStream也经常结合BufferedOutputStream。因为实际应用中写文本文件的情况占了大多数,对于java些excel的时候有jxl包,所以下面测试用不同的方式生成一个相同行数、大小相同的文件的四种不同方式。测试一下生成数据的时间,文件的大小,已经可以间接的看出消耗内存的情况。
   FileOutputStream 用于写入诸如图像数据之类的原始字节的流。

要写入字符流,请考虑使用 FileWriter。

BufferedOutputStream该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入基础输出流中,而不必为每次字节写入调用基础系统。
import java.io.BufferedOutputStream;

import java.io.File;

import java.io.FileOutputStream;

import java.io.FileWriter;



import jxl.Workbook;

import jxl.write.Label;

import jxl.write.WritableSheet;

import jxl.write.WritableWorkbook;



public class createDataFile {



  

    public static void main(String[] args) {

       // TODO Auto-generated method stub

       FileOutputStream out = null;

        FileOutputStream outSTr = null;

        BufferedOutputStream Buff=null;

        FileWriter fw = null;

        WritableWorkbook wb=null;

        int count=100000;//写文件行数

        try {

      

            long begin = System.currentTimeMillis();

            out = new FileOutputStream(new File("C:/add1.txt"));

            for (int i = 0; i < count; i++) {

                out.write("测试java 文件操作/r/n".getBytes());

            }

            out.close();

            long end = System.currentTimeMillis();

           // System.out.println((float)(new File("C:/add1.txt").length())/1024/1024);

            System.out.println("FileOutputStream执行耗时:" + (end - begin) + " 豪秒");

          

            long begin0 = System.currentTimeMillis();  

            outSTr = new FileOutputStream(new File("C:/add2.txt"));

            Buff=new BufferedOutputStream(outSTr);

            for (int i = 0; i < count; i++) {

                Buff.write("测试java 文件操作/r/n".getBytes());

            }

            Buff.flush();

            Buff.close();

            long end0 = System.currentTimeMillis();

            System.out.println("BufferedOutputStream执行耗时:" + (end0 - begin0) + " 豪秒");



          

            long begin3 = System.currentTimeMillis();

            fw = new FileWriter("C:/add3.txt");

            for (int i = 0; i < count; i++) {

                fw.write("测试java 文件操作/r/n");

            }

                fw.close();

            long end3 = System.currentTimeMillis();

            System.out.println("FileWriter执行耗时:" + (end3 - begin3) + " 豪秒");

            //生成excel

          

         

            long begin4=System.currentTimeMillis();

            wb=Workbook.createWorkbook( new  File( "c:/test.xls" ));         

            WritableSheet sheet0= wb.createSheet( "sheet1",0);

            //System.out.print(wb.getNumberOfSheets());

            int rownum=0;

            int limint=1;

            int snum=0;

            for(int i=0;i<count;i++){

              sheet0.addCell(new Label(0,rownum++,"测试java 文件操作"));  

              limint++;

              if(limint>65530){

               snum++;

                 wb.createSheet("sheet"+(wb.getNumberOfSheets()+1),wb.getNumberOfSheets()+1);//增加一个sheet

                 sheet0 = wb.getSheet(snum);

                 rownum  = sheet0.getRows();

                 limint=0;

              }

            }

            wb.write();

            wb.close();

            long end4=System.currentTimeMillis();

            System.out.println("jxl生成excel执行耗时:" + (end4 - begin4) + " 豪秒");

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            try {

            } catch (Exception e) {

                e.printStackTrace();

            }

        }

    }

}

以下结果经过多次执行,取常出现的数据,由于只是简单比较,不做详细统计。

1.    当count=1000的,即写文件1000行的时候,写出的文件大小为18.5KB:



FileOutputStream执行耗时:16 豪秒

BufferedOutputStream执行耗时:16 豪秒

FileWriter执行耗时:15 豪秒

jxl生成excel执行耗时:296 豪秒                 文件大小为47KB



2.当count=10000的,即写文件10000行的时候,写出的文件大小为185KB:



FileOutputStream执行耗时:94 豪秒

BufferedOutputStream执行耗时:15 豪秒

FileWriter执行耗时:16 豪秒

jxl生成excel执行耗时:391 豪秒                 文件大小为369KB

3.当count=100000的,即写文件100000行的时候,写出的文件大小为1856KB:



FileOutputStream执行耗时:594 豪秒

BufferedOutputStream执行耗时:94 豪秒

FileWriter执行耗时:78 豪秒

jxl生成excel执行耗时:2625 豪秒               文件大小为3592KB

4.当count=1000000的,即写文件1000000行的时候,写出的文件大小为18555KB:



FileOutputStream执行耗时:5625 豪秒

BufferedOutputStream执行耗时:1328 豪秒

FileWriter执行耗时:875 豪秒

执行生成excel的时候出现了异常:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space   



由以上数据可以看到,用文件流来写的速度比写excel的速度要快很多,生成的文件大小也比较小大小相差一半左右,而且从最后一项来看,写excel的时候对java虚拟机内存消耗也比较大,会报异常。

用流来写的三种方法中比较得出:如果不用缓冲流BufferedOutputStream,FileOutputStream写文件的是很不好的。当写 1000000行的文件的时候,FileOutputStream比FileWriter要慢4750毫秒, BufferedOutputStream比FileWriter慢553毫秒。
     不要小看这几秒的时间。当操作的数据量很大的时候,这点性能的差距就会很大了。在通用数据迁移工具导出数据库2千万条记录生成sql脚本文件的时候,性能性能相差2分钟以上。
分享到:
评论

相关推荐

    java解决大批量数据导出Excel产生内存溢出的方案

    在Java开发中,当面临大批量数据导出到Excel...通过这些方法,我们可以在处理大量数据导出到Excel时避免内存溢出问题,同时保持程序的稳定性和效率。在实际应用中,可以根据具体需求和环境选择合适的方法进行组合使用。

    Java处理100万行超大Excel文件秒级响应

    通过使用EasyExcel,我们不仅解决了处理大量Excel数据时可能出现的内存溢出问题,还大大提高了数据处理的速度。对于104万行20列的大规模Excel文件,EasyExcel能够在70秒内完成处理,极大地提高了工作效率。未来,...

    (转)大数据量的excel文件读取——2003及之前版本(含代码及示例)

    不过要注意,增加内存分配可能会导致更长的GC停顿时间,所以需权衡性能与内存使用。 5. **流式写入**:如果需要创建大量数据的Excel文件,使用SXSSF可以实现流式写入,避免一次性加载所有数据到内存。这种方式在...

    java内存分析指引07_v0.2.doc

    - **大量数据加载**:如Excel导出或大范围数据查询可能导致一次性加载过多数据,超过内存容量。 - **死循环和死递归**:这些情况可能导致程序无法正常结束,占用内存不断增长。 - **JVM内存设置不合理**:初始化...

    Memory Analyzer

    "Memory Analyzer"是一款专门针对Java应用程序的内存分析工具,它能够帮助开发者深入理解内存使用情况,定位内存泄漏问题,从而提高应用的性能和稳定性。在本文中,我们将详细探讨Memory Analyzer的功能、使用方法...

    nmon java jre nmon部署监控与分析

    2. 内存分析:监控JVM的内存使用,包括堆内存(Heap)、非堆内存(Non-Heap)等,有助于识别内存泄漏或内存不足的情况。 3. 磁盘I/O:分析磁盘读写速度,如果发现高延迟或I/O瓶颈,可能需要优化数据库查询、增加缓存...

    jprofiler使用

    jProfiler是一款强大的Java应用性能分析与内存诊断工具,它能够帮助开发者在开发阶段以及生产环境中快速定位性能瓶颈,并进行细致的调优工作。通过深入分析堆内存使用情况、CPU负载、垃圾回收等关键指标,jProfiler...

    性能学习报告

    - 分析这些指标有助于评估JVM的性能状态以及是否存在内存泄漏等问题。 #### 三、AWR收集 **AWR(Automatic Workload Repository)**是Oracle数据库内置的一种性能监控机制,用于收集数据库工作负载信息,并通过这些...

    jacob_1.18的dll和jar文件的压缩包(java)jacob_1.18的dll和jar文件的压缩包(java)

    在这个场景中,描述中提到的问题可能是由于生成的Freemarker Word文档在应用程序端无法正常打开,而使用Jacob可以提供一种解决方案。 Freemarker是一个强大的模板引擎,常用于生成动态内容,包括Word文档。然而,...

    Tomcat性能调优

    - **查看内存使用情况**:定期检查Tomcat的内存使用情况,以避免内存泄露等问题。 - **解决静态化乱码问题**:在Linux环境下,确保静态资源的编码正确无误。 通过综合运用这些技术和策略,可以显著提高Tomcat服务器...

    Java_programming_for_QA

    7. **数据处理**:Java集合框架(如ArrayList、LinkedList、HashMap等)和流API为处理大量数据提供了高效的方法,此外,Apache POI库可以用来读写Excel文件,进行数据导入导出。 8. **版本控制**:Java项目通常使用...

    酒店管理系统需求分析.docx

    酒店管理系统的开发旨在解决传统管理方式存在的诸多问题,如手工记录易出错、数据统计耗时费力等,通过自动化处理来简化工作流程,降低运营成本,同时提高客户满意度。 #### 二、项目概述 ##### 2.1 开发概述 本...

    易语言程序免安装版下载

    修改XP风格支持库,解决GDI资源泄露,以及在使用通用组件库六时组合框标题出现重影的BUG。 5. 修改扩展界面支持库一,解决树形框项目无法通过鼠标点击进入编辑状态的BUG。 6. 修改高级表格支持库,解决插入行/...

    2021-2022计算机二级等级考试试题及答案No.1291.docx

    - **健壮性**:Java设计时考虑到了安全性和健壮性,比如自动内存管理机制避免了常见的内存泄漏问题。 - **安全性**:Java提供了严格的访问控制机制,如沙箱模型,使得运行时可以检测并阻止非法行为。 - **可移植性**...

    2021-2022计算机二级等级考试试题及答案No.16264.docx

    - **定义**: 数据库的安全性是指保护数据库以防止不合法的使用所造成的数据泄露、更改或破坏。 - **措施**: - 授权机制。 - 加密技术。 - 审计跟踪。 ### 计算机的热启动 - **操作**: 在工作状态下,可以通过...

    Java经典入门教程pdf完整版

    word、 excel等运行在木机上的应用就属」桌面应用。 2:企业级应用 先解释一下企业级应用:简单的说是大规模的应用,一般使用人数较多,数据量较大, 对系统的稳定性、安全性、可扩展性和可装配性等都有比较高的要求 这是...

Global site tag (gtag.js) - Google Analytics