为什么我的程序越来越慢?

时间:2010-02-26 06:32:39

标签: java memory memory-management jvm

我正在使用该程序将数据从数据库发送到Excel文件。 它在开始时工作正常,然后变得越来越慢,最后它耗尽内存并出现以下错误:“java.lang.OutOfMemoryError:Java堆空间......”。

通过添加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();
   }

}  }

5 个答案:

答案 0 :(得分:9)

您正在某处创建对象并保留对它们的可访问引用。

您可能正在将对象添加到集合中,并且永远不会删除它们...因此集合只会增长,直到内存不足为止。当你接近最大堆大小时,垃圾收集器被过度征税以找到可用内存来重新组织事物,并且程序越接近限制就会以指数方式变慢。

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

答案 1 :(得分:2)

我非常怀疑您的程序存在内存泄漏。使用JProfiler或YourKit等探测器来检测内存泄漏。也许你忘了关闭WritableWorkbook?

http://jexcelapi.sourceforge.net/resources/javadocs/current/docs/jxl/write/WritableWorkbook.html

答案 2 :(得分:1)

当你的应用程序用尽堆空间时,在最终放弃并抛出OutOfMemoryError之前,GC会花费越来越多的时间来回收空间。我建议您执行以下操作:

  • 添加-XX:+UseGCOverheadLimit JVM选项,以使JVM在内存不足时更早失败。

  • 使用内存分析器查找可能的内存泄漏

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

如果您仍然使用更大的堆获得减速效果,则问题可能与所使用的算法有关。在这种情况下,您需要使用执行分析器来确定应用程序在大部分时间内花费的时间。

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

java -Xms512m -Xmx1024m MyProgram