2010-02-26 92 views
5

我正在使用该程序将数据从数据库发送到Excel文件。 它在开始时工作正常,然后变得越来越慢,最终它耗尽内存和下列错误代码:“java.lang.OutOfMemoryError:Java heap space ...”。为什么我的程序变得越来越慢?

该问题可以通过添加jvm堆sapce来解决。但问题是它花费了太多的时间来运行该程序。

几分钟后,它完成了一个4秒的循环,可以在开始时以0.5秒结束。我找不到解决方案使其始终以特定的速度运行。

这是我的代码问题吗?

对此有任何线索?

下面是代码:

public void addAnswerRow(List<FinalUsers> finalUsersList,WritableWorkbook book){ 

    if (finalUsersList.size() >0) { 
    try { 
     WritableSheet sheet = book.createSheet("Answer", 0); 
     int colCount = 0; 
     sheet.addCell(new Label(colCount++,0,"Number")); 
     sheet.addCell(new Label(colCount++,0,"SchoolNumber")); 
     sheet.addCell(new Label(colCount++,0,"District")); 
     sheet.addCell(new Label(colCount++,0,"SchoolName")); 
     sheet.setColumnView(1, 15); 
     sheet.setColumnView(3, 25); 

     List<Elements> elementsList = this.elementsManager.getObjectElementsByEduTypeAndQuestionnaireType(finalUsersList.get(0).getEducationType().getId(),  this.getQuestionnaireByFinalUsersType(finalUsersList.get(0).getFinalUsersType().getId())); 

     Collections.sort(elementsList, new Comparator<Elements>(){ 

      public int compare(Elements o1, Elements o2) { 

      for(int i=0; i< (o1.getItemNO().length()>o2.getItemNO().length()? o2.getItemNO().length(): o1.getItemNO().length());i++){ 
        if (CommonFun.isNumberic(o1.getItemNO().substring(0, o1.getItemNO().length()>3? 4: o1.getItemNO().length()-1)) && !CommonFun.isNumberic(o2.getItemNO().substring(0, o2.getItemNO().length()>3? 4: o2.getItemNO().length()-1))){ 
       return 1; 
        } 
       if (!CommonFun.isNumberic(o1.getItemNO().substring(0, o1.getItemNO().length()>3? 4: o1.getItemNO().length()-1)) && CommonFun.isNumberic(o2.getItemNO().substring(0,o2.getItemNO().length()>3? 4:o2.getItemNO().length()-1))){ 
       return -1; 
       } 
       if (o1.getItemNO().charAt(i)!=o2.getItemNO().charAt(i)){ 

        return o1.getItemNO().charAt(i)-o2.getItemNO().charAt(i); 
       } 
      } 
      return o1.getItemNO().length()> o2.getItemNO().length()? 1:-1; 
     }}); 

     for (Elements elements : elementsList){ 
      sheet.addCell(new Label(colCount++,0,this.getTitlePre(finalUsersList.get(0).getFinalUsersType().getId(), finalUsersList.get(0).getEducationType().getId())+elements.getItemNO()+elements.getItem().getStem())); 
     } 

     int sheetRowCount =1; 
     int sheetColCount =0; 

     for(FinalUsers finalUsers : finalUsersList){ 

      sheetColCount =0; 

      sheet.addCell(new Label(sheetColCount++,sheetRowCount,String.valueOf(sheetRowCount))); 
      sheet.addCell(new Label(sheetColCount++,sheetRowCount,finalUsers.getSchool().getSchoolNumber())); 
      sheet.addCell(new Label(sheetColCount++,sheetRowCount,finalUsers.getSchool().getDistrict().getDistrictNumber().toString().trim())); 
      sheet.addCell(new Label(sheetColCount++,sheetRowCount,finalUsers.getSchool().getName())); 

      List<AnswerLog> answerLogList = this.answerLogManager.getAnswerLogByFinalUsers(finalUsers.getId()); 


      Map<String,String> answerMap = new HashMap<String,String>(); 

      for(AnswerLog answerLog :answerLogList){ 
      if (answerLog.getOptionsId() != null) 
      { 
       answerMap.put(answerLog.getElement().getItemNO(), this.getOptionsAnswer(answerLog.getOptionsId())); 
      }else if (answerLog.getBlanks()!= null){ 

       answerMap.put(answerLog.getElement().getItemNO(), answerLog.getBlanks()); 
      }else{ 

       answerMap.put(answerLog.getElement().getItemNO(), answerLog.getSubjectiveItemContent()); 
      } 
      } 
      for (Elements elements : elementsList){ 

      sheet.addCell(new Label(sheetColCount++,sheetRowCount,null==answerMap.get(elements.getItemNO())?"0":answerMap.get(elements.getItemNO()))); 

      } 

     sheetRowCount++; 
     } 

     book.write(); 
     book.close(); 

    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (RowsExceededException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (WriteException e) { 

     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

}}

+0

你并不需要详细解释一下。例如,“我拿着两片都有一个共同的键(从下面的评论续)(studentId或东西??)并加入他们“或什么的。然后,我们可以推荐您使用合并排序来首先排序这些表格,使用磁盘空间,然后您可以在不使用大量内存的情况下遍历这两个表格...... – 2010-02-26 17:54:04

回答

9

某处你正在创建对象并保留可达对它们的引用。

您可能将对象添加到集合中,并且永远不会删除它们...所以集合只会增长,直到内存不足。当您接近最大堆大小时,垃圾收集器会被过度征税以查找可用的内存来重新组织内容,并且程序越接近极限,指数级越慢。

另外,您可能忘记每次关闭某些对象,例如工作簿。

+0

这听起来不能避免。因为它必须创建对象以保存来自数据库的数据以及GC工作未知的时间。 此外,工作簿在最后关闭:book.close() – RedWolf 2010-02-26 07:17:05

+0

该代码很难遵循...你能简单地解释你想要实现什么吗?然后我们可以看到它是否真的无法避免(如果真的无法避免,那么你仍然可以使用磁盘,所以不用担心) – 2010-02-26 08:00:48

+0

@Zwei:你可能希望将您的评论移到问题中......我不认为RedWolf会在我的回答下收到通知。 – 2010-02-26 08:38:17

1

当你的应用程序正在运行的堆空间不足,这将需要更多的时间在GC尝试之前最终放弃并引发OutOfMemoryError回收空间。我建议做以下几点:

  • 添加-XX:+UseGCOverheadLimit JVM选项,以使当它运行内存的JVM早期失效。

  • 使用内存分析器,以寻找可能的内存泄漏

  • ,如果你不能找到任何泄漏,只是增加堆大小。

如果您仍然遇到较大的堆放缓效应,则问题可能与正在使用的算法有关。在这种情况下,您需要使用执行分析器来确定您的应用程序花费大部分时间。

[理论:如果您的addAnswerRow被重复调用,则问题可能与重复打开每个调用每个addAnswerRow的Xcel电子表格文件变大有关。每次打开文件时都有可能将其整个加载到内存中。]

+0

当addAnswerRow()被调用一次时,创建一个excel文件。我错误地将该函数命名为addAnswerRow(),它应该被称为createAnswerExcel()。它确实被反复调用。 我会按照你的建议。 :) – RedWolf 2010-02-26 12:28:36

0

使用-verbose:gc JVM选项可轻松检查减速是否由GC抖动引起。

0

增加堆大小可能会有帮助。您可以尝试通过包含-Xms和-Xmx参数来设置最小和最大堆大小。以下命令将最小堆大小设置为512 MB,最大堆为1024 MB。

的java -Xms512m -Xmx1024m MyProgram