2012-07-27 6 views
1

MySQL 데이터베이스에 연결되는 Tomcat 6에서 실행되는 Java 프로젝트에서 작업하고 있습니다. 모든 절차는 고객의 서버에서 로컬 테스트를 수행 할 때와 마찬가지로 수행해야합니다. 그러나 한 가지 예외가 있습니다. 이는 보고서를 생성하기 위해 많은 양의 데이터를 검색하는 하나의 프로 시저에 대한 것입니다. 스토어드 프로 시저는 MySQL에서 실행될 때 13 분 정도 걸립니다. 응용 프로그램을 로컬에서 실행하고 온라인 데이터베이스에 연결할 때 절차가 작동하지만 클라이언트의 서버에서 실행될 때만 작동합니다.Java storedProcedure가 OutOfMemoryError로 중지되었습니다.

클라이언트가 자신의 서버를 보호하기 때문에 제한적으로 제어 할 수 있지만 문제를 해결하기를 원합니다. 로그 파일을 검사 할 때 저장된 프로 시저를 실행하는 함수에서 오류가 발생하지 않습니다. 그리고 코드에 디버그 로그를 두는 것은 실행 호출에 도달하지만 호출 직후 디버그를 기록하지 않고 catch에서 오류를 기록하지는 않지만 finally 섹션에 들어가는 것을 보여줍니다.

그들은 MySQL 로그에 시간 초과 오류가 없다고 주장합니다.

누구든지이 문제의 원인에 대한 아이디어가 있으면 도움을받을 수 있습니다.

갱신 : 서버 관리자에게 몇 가지 잔소리 후

, 나는 마침내 카탈 로그에 액세스 할 수있어, 그 로그에, 나는 마침내 어떤 의미가 오류 발견했습니다

Exception in thread "Thread-16" java.lang.OutOfMemoryError: Java heap space 
     at java.util.Arrays.copyOf(Arrays.java:2894) 
     at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:117) 
     at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:407) 
     at java.lang.StringBuffer.append(StringBuffer.java:241) 
     at be.playlane.mink.database.SelectExportDataProcedure.bufferField(SelectExportDataProcedure.java:68) 
     at be.playlane.mink.database.SelectExportDataProcedure.extractData(SelectExportDataProcedure.java:54) 
     at org.springframework.jdbc.core.JdbcTemplate.processResultSet(JdbcTemplate.java:1033) 
     at org.springframework.jdbc.core.JdbcTemplate.extractReturnedResultSets(JdbcTemplate.java:947) 
     at org.springframework.jdbc.core.JdbcTemplate$5.doInCallableStatement(JdbcTemplate.java:918) 
     at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:876) 
     at org.springframework.jdbc.core.JdbcTemplate.call(JdbcTemplate.java:908) 
     at org.springframework.jdbc.object.StoredProcedure.execute(StoredProcedure.java:113) 
     at be.playlane.mink.database.SelectExportDataProcedure.execute(SelectExportDataProcedure.java:29) 
     at be.playlane.mink.service.impl.DefaultExportService$ExportDataRunnable.run(DefaultExportService.java:82) 
     at java.lang.Thread.run(Thread.java:636) 

이 정보는 응용 프로그램 로그에 기록되지 않으므로 try catch 내에서 래핑 된 경우에도 마찬가지입니다. 이제 오류를 기반으로, 문제는이 방법 withing에있다 :이 기능의

public Object extractData(ResultSet rs) throws SQLException, DataAccessException 
    { 
    StringBuffer buffer = new StringBuffer(); 

    try 
    { 
     // get result set meta data 
     ResultSetMetaData meta = rs.getMetaData(); 
     int count = meta.getColumnCount(); 

     // get the column names; column indices start from 1 
     for (int i = 1; i < count + 1; ++i) 
     { 

     String name = meta.getColumnName(i); 
     bufferField(name, i == count, buffer); 
     } 

     while (rs.next()) 
     { 

     // get the column values; column indices start from 1 
     for (int i = 1; i < count + 1; ++i) 
     { 
      String value = rs.getString(i); 
      bufferField(value, i == count, buffer); 
     } 
     } 
    } 
    catch (Exception e) 
    { 
     logger.error("Failed to extractData SelectExportDataProcedue: ", e); 
    } 

    return buffer.toString(); 
    } 

    private void bufferField(String field, boolean last, StringBuffer buffer) 
    { 
    try 
    { 
     if (field != null) 
     { 

     field = field.replace('\r', ' '); 
     field = field.replace('\n', ' '); 

     buffer.append(field); 
     } 

     if (last) 
     { 
     buffer.append('\n'); 
     } 
     else 
     { 
     buffer.append('\t'); 
     } 
    } 
    catch (Exception e) 
    { 
     logger.error("Failed to bufferField SelectExportDataProcedue: ", e); 
    } 
    } 

목표는 (높은 수준에서 발생하는) 엑셀 파일에 특정 결과 집합을 내보내는 것입니다.

누구나이를 최적화하는 데 도움이되는 정보가 있으면 매우 환영합니다. 당신은 응용 프로그램이 충돌되어 로그인하지 않는 이유

Exception in thread "Thread-16" java.lang.OutOfMemoryError: Java heap space 

(스레드, 구체적으로) :

+1

서버 액세스가 없으면이 문제가 발생합니다. 신속하게 실행되고 테스트 환경을 통해 실행되는 TOP 100과 같이 수정 된 저장 프로 시저의 단축 된 하위 집합을 수행 할 수 있습니까? 또는 응용 프로그램에 일부 로깅을 추가하고 로그를 통해 디버그하십시오. 응용 프로그램이 예외를 먹고있을 수도 있습니다. –

+0

업데이트에서 볼 수 있듯이 나는 의미있는 오류 로그를 포함하고있는 catalina 로그를 마침내 보유하고 있습니다. 그래서 지금 문제를 찾아 낼 수 있었지만, 이것을 최적화하는 방법을 잘 모르겠습니다. – Andy

+0

잡을 수없는 이유는 '오류'이고 '예외'가 아니라는 것입니다! (no, catch (Error e)를 추가하는 것은 ** 정확한 해결책이 아니다.) 또한 문제의 근원이 될 거대한'String'을 하나 만들면, 어디서나 데이터를 스트리밍해야한다. 당신은 하나의 커다란 객체를 할당하는 대신 그것을 원한다. –

답변

2

좋아, 당신의 스택 트레이스는 당신에게 대답을 제공합니다. 귀하의 설명을 보면, 페이징 할 필요가있는 거대한 데이터 세트가있는 것처럼 들립니다.

 while (rs.next()) 
     { 

     // get the column values; column indices start from 1 
     for (int i = 1; i < count + 1; ++i) 
     { 
      String value = rs.getString(i); 
      bufferField(value, i == count, buffer); 
     } 
     } 

여기가 스레드가 죽는 곳입니다 (아마). 기본적으로 StringBuffer 메모리가 부족합니다. 그것을 정정하는 것에 관해서는, 엄청난 양의 옵션이 있습니다. 당신은 이미 그 일을하는 경우 장치에 더 많은 RAM을 던져, How to set the maximum memory usage for JVM?

또는

에서 : JVM (여기 링크)를 구성하여 하나 (클라이언트 측의 문제에 더 많은 메모리를 던져. 프로그래밍 관점에서 보았을 때, 이것은 보고서의 지옥이라고 할 수 있습니다. 가능한 경우 최종 버퍼링보다는 MySQL에 대한 수치 계산을 수행 할 수 있습니다. 거대한 보고서 인 경우이를 스트리밍하는 것이 좋습니다. 파일을 채운 다음 버퍼링 된 스트림을 통해 읽음으로써 보고서를 채우십시오.

보고서가 무엇인가에 달려 있습니다. 작 으면 mi에 대한 SQL 작업이 더 많을 것입니다. 결과 집합을 최소화하십시오.거대한 보고서 인 경우 버퍼링이 다른 옵션입니다.

누락 된 다른 가능성은 구현에 따라 ResultSet이 아마도 버퍼링된다는 것입니다. 즉, 문자열을 모두 읽지 않고 ResultSet 객체를 직접 가져 와서 인쇄 할 수 있습니다. 물론 이것의 단점은 SQL 예외가 누설되면 보고서가 삭제된다는 것입니다.

행운을 빈다. 우선 메모리 옵션을 시도해 보겠다. 당신은 128과 같이 작고 무언가 작은 것으로 달릴 수도 있고 간단 할 것입니다 (저는 원격으로 관리되는 머신에서 이런 일이 많이 일어난 것을 보았습니다).

+0

늦게 답장을 드려 죄송합니다. 이 파일을 파일로 스트리밍하는 것이이 작업을위한 최선의 방법이라고 생각했습니다. 대답 tho 주셔서 감사합니다. – Andy

관련 문제