Почему моя программа становится все медленнее и медленнее? - PullRequest
5 голосов
/ 26 февраля 2010

Я использую программу для отправки данных из базы данных в файл 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();
   }

} }

Ответы [ 5 ]

9 голосов
/ 26 февраля 2010

Где-то вы создаете объекты и сохраняете достижимые ссылки на них.

Вы, вероятно, добавляете объекты в коллекцию и никогда не удаляете их ... поэтому коллекция просто увеличивается до тех пор, пока не закончится память. Когда вы приближаетесь к максимальному размеру кучи, сборщик мусора перегружается, чтобы найти свободную память для реорганизации вещей, и программа становится экспоненциально медленнее, чем ближе вы подходите к пределу.

Кроме того, возможно, вы забываете каждый раз закрывать некоторые объекты, например, рабочую книгу.

2 голосов
/ 26 февраля 2010

Я подозреваю, что в вашей программе есть утечка памяти. Используйте профилировщик, например JProfiler или YourKit, чтобы обнаружить утечку памяти. Может быть, вы забыли закрыть WritableWorkbook?

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

1 голос
/ 26 февраля 2010

Когда вашему приложению не хватает места в куче, в GC потребуется все больше и больше времени, чтобы попытаться освободить пространство, прежде чем в конечном итоге отказаться и выбросить OutOfMemoryError. Я рекомендую сделать следующее:

  • добавьте параметр -XX:+UseGCOverheadLimit JVM, чтобы JVM отказывал раньше, когда ему не хватает памяти.

  • использовать профилировщик памяти для поиска возможных утечек памяти

  • если вы не можете найти никаких утечек, просто увеличьте размер кучи.

Если вы по-прежнему получаете эффекты замедления с большей кучей, проблема может быть связана с используемыми алгоритмами. В этом случае вам нужно использовать профилировщик выполнения, чтобы выяснить, где ваше приложение проводит большую часть своего времени.

[Теория. Если ваш addAnswerRow вызывается неоднократно, проблема может быть связана с повторным открытием файла электронной таблицы Xcel, который увеличивается с каждым вызовом addAnswerRow. Возможно, что каждый раз, когда вы открываете файл, он полностью загружается в память.]

0 голосов
/ 16 марта 2010

Может помочь увеличение размера кучи. Вы можете попробовать установить минимальный и максимальный размер кучи, включив аргументы -Xms и -Xmx. Следующая команда установит минимальный размер кучи равным 512 МБ, а максимальный - 1024 МБ.

Java -Xms512m -Xmx1024m MyProgram

0 голосов
/ 26 февраля 2010

Используйте параметр -verbose: gc JVM, чтобы легко проверить, вызвано ли замедление перегрузкой GC.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...