石英多次执行后,Java Excel POI停止

时间:2012-11-21 08:12:32

标签: java profiling apache-poi quartz-scheduler

我想对此有一些见解。

我有一个程序,可以从数据库读取和写入excel文件。它的执行基于使用Quartz api的计时器,并在每周的每周二触发。问题是,当我通过安排它每小时执行一次作业来测试它时,程序在编写excel文件的过程中几次执行后突然停止。这是我写的excel代码。

try {
        FileInputStream file = new FileInputStream(excelFile);
        POIFSFileSystem myFileSystem = new POIFSFileSystem(file);
        HSSFWorkbook workbook = new HSSFWorkbook(myFileSystem);
        HSSFSheet worksheet = workbook.getSheetAt(0);
        this.cellStyle00 = workbook.createCellStyle();
        HSSFDataFormat df = workbook.createDataFormat();
        this.cellStyle00.setDataFormat(df.getFormat("00"));

for(int i = 0;i<Access.size();i++){
         AccessorMethods SetGet = (AccessorMethods)
                    InstlibAccessor.get(i);

    HSSFRow row = worksheet.createRow(worksheet.getPhysicalNumberOfRows());
    HSSFCell cell = row.createCell(0);

    cell.setCellValue(new Double(SetGet.getOne()));
    cell.setCellStyle(cellStyle00);


  //other set value codes....

}
FileOutputStream fileOut = new FileOutputStream(fileName + ".xls");
workbook.write(fileOut);
 fileOut.flush();
 fileOut.close(); 

 //catch statements follow
 //end

命令行输出和netbeans输出并不表示任何错误,如内存不足等等。程序没有结束..它只是,停止..就像jvm正在进行无限循环...更多地了解这个话题,这是我的计划的简要流程。

  1. 用户执行调度程序
  2. 在所需的时间,调度程序执行程序(调度程序和“程序”是两个不同的程序/ jar文件。调度程序只调用jar)
  3. 程序首先创建excel文件
  4. 然后读取数据库1.数据库包含80K行
  5. 对于每一行,如果满足某个条件,则会读取数据库2和3
  6. 然后它一次将它存储在一个arraylist对象1000中(我试图避免任何内存问题,所以我按批次存储它)
  7. 然后我按批次写出来,一次写出1000(这是它停止的部分)
  8. 完成读写操作后,等待调度程序再次调用它...如果它到达此步骤我是一个快乐的程序员=)
  9. 以下是我发现的一些观察结果;

    1. 程序通常在程序的第4到第6次执行时停止(这是在不间断运行调度程序4到6个小时后)
    2. 它会像在第34行或第24或第15等等那样在excel中随意写入等等......
    3. 当我在没有调度程序的情况下执行程序时,不会发生此错误。我可以整天手动执行它(我做了,它不是很有趣)没有任何错误。
    4. 输出excel文件显示大小为0bytes
    5. 例如,如果我安排它每小时运行一次,那么它停止了。它仍会在接下来的几个小时内运行但会停止,并且与之前的运行相比停在不同的点。
    6. 可能导致此问题的原因。内存泄漏或许更简单?

      其他信息

      我通过导入其他程序的类来实现Quartz调度程序并将其作为作业运行。这是触发器的代码

      JobDetail job = newJob(ExtractorSchedulerJobUtilTester.class)
                  .withIdentity("job1", "group1")
                  .build();
      
          CronTrigger trigger = newTrigger()
                  .withIdentity("trigger1", "group1")
                  .withSchedule(cronSchedule("0 0/2 * 1/1 * ? *"))
                  .build();
      
          Date ft = sched.scheduleJob(job, trigger);
              sched.start();
      

      和工作

      public class ExtractorSchedulerJobUtilTester implements Job {
          public void execute(JobExecutionContext context)
              throws JobExecutionException {
          theProgram program= new theProgram();
      
          program.main();
      
          JobKey jobKey = context.getJobDetail().getKey();
          }
      }
      

      是否可能;

      1. 应用程序正在耗尽我的记忆力并崩溃
      2. 我只在Quartz作业中使用了一个“program”实例,它在作业的第一次运行时被初始化,并且该作业的所有后续执行都从该实例中引用,从而最大化了内存。
      3. 它的数据库(AS400)相关(我怀疑因为它在写excel时停止了。)
      4. 电脑太累了,决定休息一下。
      5. 更新 - 12/28/2012

        新年快乐男孩/加尔斯!!

        对不起,我花了一些时间才回到这里......(当世界将在21日结束时,为什么还要浪费时间。当它没有时它是苦乐参半的)

        我用netbeans profiler描述了我的程序,并使用内存分析器获得了以下数据

        memory dump

        我在第一张图中注意到,我的程序在每次迭代时消耗大约75MB的堆大小(如粉色阴影所示)。这是否意味着程序的消耗内存每次迭代增加75mb?经过几次迭代后,会占用大量内存,从而影响程序的执行。我正在尝试进行堆转储..一旦我设法让它运行,我就会发布它。

        附加信息:我尝试使用仅运行Quartz的探测器(不会触发任何东西),系统使用率相对较低,每次迭代的大小都不会增加。

        我终于设法获得堆转储。我进行了2次转储,首先是第一次迭代发生时,第二次是下一次迭代。我注意到我的两个classess的实例之间存在很大差异,如下所示

        hash dump

        谢谢!

1 个答案:

答案 0 :(得分:0)

经过大量的诅咒,祈祷和搜索后,我想我已经找到了解决方法。我所做的是在Quartz作业类的末尾添加System.gc();。因此,每次程序完成作业时调用垃圾回收。这只是一个可能的解决方案,而不是一个具体的答案,因为我仍然占用了大量的堆内存(我相信在我的代码的混乱中仍有一些内存泄漏)。但是,System.gc();我消耗的费用要少得多。我只是不确定这是怎么发生的。从逻辑上讲,我认为GC只会影响内存分配,而不会影响程序的内存性能。见下图;顶部的图表是带有GC的图表,而底部是没有的图表。

enter image description here

正如您所看到的那样,GC的堆内存比没有GC的堆内存少。我假设内存使用量仍与GC相同,但一旦调用GC,使用的堆空间将下降。我现在将使用这个解决方案,直到出现更好的答案。