2010-02-26 94 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