2013-10-17 2 views
7

아래 프로그램을 실행하려고하면 java.lang.OutOfMemoryError : GC 오버 헤드 한도를 초과했습니다. 이 프로그램의 주 방법은 지정된 디렉토리에 액세스하여 .xlsx가 포함 된 모든 파일을 반복합니다. 이것은 다른 로직보다 먼저 테스트 할 때 잘 동작합니다. 그리고 그것은 xlsx를 xlsx 파일을 csv로 변환하고 기존 파일에 추가하는 xlsx 메서드도 잘 동작합니다. 그러나 이것을 for 루프에 넣으면이 예외가 생깁니다. , 내 유일한 추측 지금 그게java.lang.OutOfMemoryError : GC 오버 플로우 한도 초과 리더

File inputFile = new File("C:\\Users\\edennis.AD\\Desktop\\test\\"+nameOfFile); 

: 나는 그것이 XLSX를 개설 한 후 충돌이 그것을 추측하고 그것에게 CSV 및 아마 어떻게 든이 줄을 닫아야 할 두 번째를 열려면 그 시간을 변환하고 루프의 두 x 째 반복이 오면이 파일이 간섭하고 있다고 가정합니다. 나는 엑셀 파일을 조작하기 위해 아파치 POI 라이브러리를 사용하고있다. 미리 감사드립니다.

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import org.apache.poi.ss.usermodel.Cell; 
import org.apache.poi.ss.usermodel.Row; 
import org.apache.poi.xssf.usermodel.XSSFSheet; 
import org.apache.poi.xssf.usermodel.XSSFWorkbook; 

public class ExcelMan { 

    public static void main(String[] args) throws FileNotFoundException { 



     int i =0; 


      File dir = new File("C:\\Users\\edennis.AD\\Desktop\\test\\"); 
      for (File child : dir.listFiles()) { 

      //initializing whether the sheet sent to method is first or not, and //counting iterations for each time the for loop as run 

      boolean firstSheet = true; 
      i++; 

      String nameOfFile = child.getName(); 

      if (nameOfFile.contains(".xlsx")){ 

      System.out.println(nameOfFile); 

       if (i != 0) 
       firstSheet = false; 


       File inputFile = new File("C:\\Users\\edennis.AD\\Desktop\\test\\"+nameOfFile); 

       // writing excel data to csv 
       File outputFile = new File("C:\\Users\\edennis.AD\\Desktop\\test\\memb.csv"); 
       xlsx(inputFile, outputFile, firstSheet); 


      } 


      // } 

     } 


    } 




     static void xlsx(File inputFile, File outputFile, boolean firstSheet) { 
      // For storing data into CSV files 
      StringBuffer data = new StringBuffer(); 


      try { 
       FileOutputStream fos = new FileOutputStream(outputFile, true); 
       // Get the workbook object for XLSX file 
       XSSFWorkbook wBook = new XSSFWorkbook(new FileInputStream(inputFile)); 
       // Get first sheet from the workbook 


       XSSFSheet sheet = wBook.getSheetAt(7); 
       Row row; 
       Cell cell; 
       // Iterate through each rows from first sheet 
       java.util.Iterator<Row> rowIterator = sheet.iterator(); 

       while (rowIterator.hasNext()) { 

        if (firstSheet != true) 
         rowIterator.next(); 

        row = rowIterator.next(); 

        // For each row, iterate through each columns 
        java.util.Iterator<Cell> cellIterator = row.cellIterator(); 
        while (cellIterator.hasNext()) { 


         cell = cellIterator.next(); 

         switch (cell.getCellType()) { 
          case Cell.CELL_TYPE_BOOLEAN: 
           data.append(cell.getBooleanCellValue() + "^"); 

           break; 
          case Cell.CELL_TYPE_NUMERIC: 
           data.append(cell.getNumericCellValue() + "^"); 

           break; 
          case Cell.CELL_TYPE_STRING: 
           data.append(cell.getStringCellValue() + "^"); 
           break;        
          case Cell.CELL_TYPE_BLANK: 
           data.append("" + "^"); 
           break; 
          default: 
           data.append(cell + "^"); 

         } 


        } 
        data.append("\r\n"); 

       } 

       fos.write(data.toString().getBytes()); 
       fos.close(); 


      } catch (Exception ioe) { 
       ioe.printStackTrace(); 
      } 
     } 



} 

추가 정보 : 아래

가이 약 30 정도 디렉토리와 가장 큰 하나의 약이 될 것입니다, 엑셀 파일이 꽤 큰 있습니다

MR.xlsx 
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 
     at org.apache.xmlbeans.impl.store.Cur$CurLoadContext.attr(Cur.java:3039) 
     at org.apache.xmlbeans.impl.store.Cur$CurLoadContext.attr(Cur.java:3060) 
     at org.apache.xmlbeans.impl.store.Locale$SaxHandler.startElement(Locale.java:3250) 
     at org.apache.xmlbeans.impl.piccolo.xml.Piccolo.reportStartTag(Piccolo.java:1082) 
     at org.apache.xmlbeans.impl.piccolo.xml.PiccoloLexer.parseAttributesNS(PiccoloLexer.java:1802) 
     at org.apache.xmlbeans.impl.piccolo.xml.PiccoloLexer.parseOpenTagNS(PiccoloLexer.java:1521) 
     at org.apache.xmlbeans.impl.piccolo.xml.PiccoloLexer.parseTagNS(PiccoloLexer.java:1362) 
     at org.apache.xmlbeans.impl.piccolo.xml.PiccoloLexer.parseXMLNS(PiccoloLexer.java:1293) 
     at org.apache.xmlbeans.impl.piccolo.xml.PiccoloLexer.parseXML(PiccoloLexer.java:1261) 
     at org.apache.xmlbeans.impl.piccolo.xml.PiccoloLexer.yylex(PiccoloLexer.java:4808) 
     at org.apache.xmlbeans.impl.piccolo.xml.Piccolo.yylex(Piccolo.java:1290) 
     at org.apache.xmlbeans.impl.piccolo.xml.Piccolo.yyparse(Piccolo.java:1400) 
     at org.apache.xmlbeans.impl.piccolo.xml.Piccolo.parse(Piccolo.java:714) 
     at org.apache.xmlbeans.impl.store.Locale$SaxLoader.load(Locale.java:3439) 
     at org.apache.xmlbeans.impl.store.Locale.parseToXmlObject(Locale.java:1270) 
     at org.apache.xmlbeans.impl.store.Locale.parseToXmlObject(Locale.java:1257) 
     at org.apache.xmlbeans.impl.schema.SchemaTypeLoaderBase.parse(SchemaTypeLoaderBase.java:345) 
     at org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument$Factory.parse(Unknown Source) 
     at org.apache.poi.xssf.usermodel.XSSFSheet.read(XSSFSheet.java:138) 
     at org.apache.poi.xssf.usermodel.XSSFSheet.onDocumentRead(XSSFSheet.java:130) 
     at org.apache.poi.xssf.usermodel.XSSFWorkbook.onDocumentRead(XSSFWorkbook.java:286) 
     at org.apache.poi.POIXMLDocument.load(POIXMLDocument.java:159) 
     at org.apache.poi.xssf.usermodel.XSSFWorkbook.<init>(XSSFWorkbook.java:207) 
     at ExcelMan.xlsx(ExcelMan.java:71) 
     at ExcelMan.main(ExcelMan.java:47) 

스택 트레이스입니다 170MB.이 파일 크기는 POI에서 변경해야합니까?

+0

전체 스택 추적을 추가 할 수 있습니까? – fvrghl

+3

자바 힙을 늘려야합니다. http://stackoverflow.com/questions/1098488/jvm-heap-parameters –

+1

이벤트 기반 모델로 전환해야합니다. 현재 사용중인 API로 큰 파일을 처리 할 수 ​​없습니다. –

답변

3

당신의 엑셀 파일의 크기는 얼마입니까? 한 번 비슷한 문제가 발생하여 csvxls 개 생성했습니다. 제 경우에는 event driven model으로 전환해야하고 XSSF 및 SAX (이벤트 API)을 살펴보아야합니다.

Further effort on HSSF is going to focus on the following major areas:

  • Performance: POI currently uses a lot of memory for large sheets.
+0

Excel 파일의 크기는 어느 정도입니까? OP는 잘하면 RAM의 4 기가 바이트를 사용하여 170 메가 바이트 파일을 처리 할 수 ​​있어야합니다 ... 나는 희망 ... – nneonneo

+0

@ nneonneo 내가 정확히 그의 크기에 대해 파일을 기억합니다. 나중에 그것을 시도해라, 아마 나는 그 파일 중의 1 개를 아직도 가지고있다. –

1

파일이 닫혀 할 필요가 없습니다 : 너무

(-Xmx8g으로) 메모리가 링크 된 사이트에서 견적을 달렸다. 당신이 그들에 대한 참조를 유지하지 않는 한 그들은 범위를 벗어나는대로 GCd 될 것입니다.

라인 if (i != 0)은이 조건을 만족하기 전에 변수 i를 적어도 한 번 증분하기 때문에 항상 true로 평가됩니다. 따라서 firstSheet는 항상 false로 설정됩니다.

선은

File inputFile = new File("C:\\Users\\edennis.AD\\Desktop\\test\\"+nameOfFile); 

은 새 파일을 만드는 것입니다. 그러나이 경로에 대한 파일 객체는 이미 child

으로 표시됩니다. 파일 객체를 새로 만드는 동일한 파일과 항상 초기 디렉토리를 반복 할 때마다 새 FileOutputStream을 작성합니다. 쓰기는 같은 파일에 있습니다.

finally 블록에서 FileOutputStream을 종료하지 않으며 오류 조건에서 FileOutputStream을 제대로 닫지 않을 수 있습니다.

문자열 작성에 동기화 된 메서드가 필요하지 않는 한 StringBuffer 대신 StringBuilder를 사용하십시오.

중간 StringBuilder 대신 FileWriter를 사용해보십시오.대신 빌더로 작성하는 대신 data.append 사용을 writer.print 또는 writer.println 참고를하는

PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(outputFile, true)))) 

를 사용의 PrintWriter 및 버퍼 작가 래퍼가 반드시 필요하지만, 유용하지 않습니다.

XSSFWorkbook javadocs에서 생성자 옵션을 참조하면 "InputStream을 사용하면 File을 사용하는 것보다 더 많은 메모리가 필요하므로 File을 사용할 수 있으면 대신 'example follows'와 같은 것을 사용해야합니다." http://poi.apache.org/apidocs/org/apache/poi/xssf/usermodel/XSSFWorkbook.html#XSSFWorkbook(java.io.InputStream)

다른 모든 것이 실패 할 경우 힙 크기를 늘리면 해결할 수 있습니다. 현재 테스트중인 파일보다 훨씬 큰 파일의 가능성이 없다고 가정합니다. Increase heap size in Java

관련 문제