2009-11-30 19 views
7

Tomcat에서 Java 웹 응용 프로그램을 실행하고 있습니다. 이 응용 프로그램은 Quartz 프레임 워크를 사용하여 일정한 간격으로 cron 작업을 예약합니다. 이 cron 작업에는 JDOM API를 사용하여 수행중인 4MB 이상의 xml 파일을 구문 분석하는 작업이 포함됩니다. xml 파일에는 약 3600 개의 노드가 파싱되어 결과적으로 DB에서 업데이트 될 데이터가 순차적으로 처리됩니다.
파일의 거의 절반을 파싱 한 후 응용 프로그램에서 메모리 부족 예외가 발생합니다. 동일한 스택 추적은 다음과 같습니다.Java 메모리 부족 예외

Exception in thread "ContainerBackgroundProcessor[StandardEngine[Catalina]]" java.lang.OutOfMemoryError: Java heap space 
     at java.util.Arrays.copyOfRange(Arrays.java:3210) 
     at java.lang.String.<init>(String.java:216) 
     at java.lang.StringBuffer.toString(StringBuffer.java:585) 
     at org.netbeans.lib.profiler.server.ProfilerRuntimeMemory.traceVMObjectAlloc(ProfilerRuntimeMemory.java:170) 
     at java.lang.Throwable.getStackTraceElement(Native Method) 
     at java.lang.Throwable.getOurStackTrace(Throwable.java:590) 
     at java.lang.Throwable.getStackTrace(Throwable.java:582) 
     at org.apache.juli.logging.DirectJDKLog.log(DirectJDKLog.java:155) 
     at org.apache.juli.logging.DirectJDKLog.error(DirectJDKLog.java:135) 
     at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1603) 
     at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1610) 
     at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1590) 
     at java.lang.Thread.run(Thread.java:619) 
Exception in thread "*** JFluid Monitor thread ***" java.lang.OutOfMemoryError: Java heap space 
     at java.util.Arrays.copyOf(Arrays.java:2760) 
     at java.util.Arrays.copyOf(Arrays.java:2734) 
     at java.util.Vector.ensureCapacityHelper(Vector.java:226) 
     at java.util.Vector.add(Vector.java:728) 
     at org.netbeans.lib.profiler.server.Monitors$SurvGenAndThreadsMonitor.updateSurvGenData(Monitors.java:230) 
     at org.netbeans.lib.profiler.server.Monitors$SurvGenAndThreadsMonitor.run(Monitors.java:169) 
Nov 30, 2009 2:22:05 PM org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor processChildren 
SEVERE: Exception invoking periodic operation: 
java.lang.OutOfMemoryError: Java heap space 
     at java.lang.StringCoding$StringEncoder.encode(StringCoding.java:232) 
     at java.lang.StringCoding.encode(StringCoding.java:272) 
     at java.lang.String.getBytes(String.java:946) 
     at java.io.UnixFileSystem.getLastModifiedTime(Native Method) 
     at java.io.File.lastModified(File.java:826) 
     at org.apache.catalina.startup.HostConfig.checkResources(HostConfig.java:1175) 
     at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1269) 
     at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:296) 
     at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:118) 
     at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1337) 
     at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1601) 
     at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1610) 
     at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1590) 
     at java.lang.Thread.run(Thread.java:619) 
ERROR [JobRunShell]: Job updateVendorData.quoteUpdate threw an unhandled Exception: 
java.lang.OutOfMemoryError: Java heap space 
     at java.util.Arrays.copyOfRange(Arrays.java:3210) 
     at java.lang.String.<init>(String.java:216) 
     at java.lang.StringBuffer.toString(StringBuffer.java:585) 
     at org.apache.commons.dbcp.PoolingConnection$PStmtKey.hashCode(PoolingConnection.java:296) 
     at java.util.HashMap.get(HashMap.java:300) 
     at org.apache.commons.pool.impl.GenericKeyedObjectPool.decrementActiveCount(GenericKeyedObjectPool.java:1085) 
     at org.apache.commons.pool.impl.GenericKeyedObjectPool.returnObject(GenericKeyedObjectPool.java:882) 
     at org.apache.commons.dbcp.PoolablePreparedStatement.close(PoolablePreparedStatement.java:80) 
     at org.apache.commons.dbcp.DelegatingStatement.close(DelegatingStatement.java:168) 
     at com.netcore.smsapps.stock.db.CompanyDaoImpl.updateCompanyQuote(CompanyDaoImpl.java:173) 
     at com.netcore.smsapps.stock.vendor.MyirisVendor.readScripQuotes(MyirisVendor.java:159) 
     at com.netcore.smsapps.stock.update.StockUpdateData.execute(StockUpdateData.java:38) 
     at org.quartz.core.JobRunShell.run(JobRunShell.java:207) 
     at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:525) 
DEBUG [ExceptionHelper]: Detected JDK support for nested exceptions. 
ERROR [ErrorLogger]: Job (updateVendorData.quoteUpdate threw an exception. 
org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: java.lang.OutOfMemoryError: Java heap space] 
     at org.quartz.core.JobRunShell.run(JobRunShell.java:216) 
     at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:525) 
Caused by: java.lang.OutOfMemoryError: Java heap space 
     at java.util.Arrays.copyOfRange(Arrays.java:3210) 
     at java.lang.String.<init>(String.java:216) 
     at java.lang.StringBuffer.toString(StringBuffer.java:585) 
     at org.apache.commons.dbcp.PoolingConnection$PStmtKey.hashCode(PoolingConnection.java:296) 
     at java.util.HashMap.get(HashMap.java:300) 
     at org.apache.commons.pool.impl.GenericKeyedObjectPool.decrementActiveCount(GenericKeyedObjectPool.java:1085) 
     at org.apache.commons.pool.impl.GenericKeyedObjectPool.returnObject(GenericKeyedObjectPool.java:882) 
     at org.apache.commons.dbcp.PoolablePreparedStatement.close(PoolablePreparedStatement.java:80) 
     at org.apache.commons.dbcp.DelegatingStatement.close(DelegatingStatement.java:168) 
     at com.netcore.smsapps.stock.db.CompanyDaoImpl.updateCompanyQuote(CompanyDaoImpl.java:173) 
     at com.netcore.smsapps.stock.vendor.MyirisVendor.readScripQuotes(MyirisVendor.java:159) 
     at com.netcore.smsapps.stock.update.StockUpdateData.execute(StockUpdateData.java:38) 
     at org.quartz.core.JobRunShell.run(JobRunShell.java:207) 

이로 인해 내 tomcat도 충돌합니다. 문제 진단에 나를 도와주십시오. 나는 심지어 넷빈즈에서 프로파일 링을 가능하게 만들었지 만, 심지어 그 것이 추락 한 것처럼 보인다. Tomcat에 할당 된 기본 메모리를 유지했습니다. 메모리 누수가 발생합니까? DB가 postgres이고 JDK가 1.6.0_15입니다.

감사합니다, 미트 당신은 XML 파일을 구문 분석하는 DOM을 사용

+4

이 질문과 이전 질문에 대한 답변을 선택하는 것을 잊지 마십시오. 당신은 이미 7 가지 질문을했고 그들 중 누구도 좋은 대답을 가지고 있지 않았습니까? –

답변

5

매번는, 당신이 그것을 처리하기 위해 같은 크기 사용할 메모리와 DOM 인프라에 전체 파일을로드 할 수 있습니다, 그래서 두 배 정도 소비하는 것 메모리가 파일 크기보다 큽니다.

이벤트 기반 파서 인 SAX를 사용해야합니다. 이것이 처음에는 이해하기 어려울 지 모르지만, 메모리를 현재 파싱 노드로 유지하기 때문에 매우 효과적입니다.

Java에 StAX과 같은 SAX 구현이있는 것 같습니다. 도움이 되었기를 바랍니다.

+0

안녕하세요 루벤스, 나는 큰 XML을 파싱하기 위해 JDOM을 사용하고 있으며 내부적으로 SAX 파서를 사용합니다. 내 구문 분석 코드는 다음과 같습니다. SAXBuilder builder = new SAXBuilder(); 문서 doc = builder.build (inputResource); 요소 elem = doc.getRootElement(); – Amit

+1

DOM 파서가 SAX를 사용하기 때문에 순차적으로 XML을 읽고 '..','//'및 stuff –

+0

StAX와 SAX는 서로 다른 API입니다. 그러나 둘 다 메모리 사용을 줄이는 데 사용할 수 있습니다. (SAX는 StAX 사용자 코드에서 콜백을 사용하여 다음에 파싱 된 토큰을 묻습니다.) –

0

어딘가에 반복적 인 배열 복사본이 있는지, 실수로 거기에 남아 있습니까? 아마도 다른 스레드에서?

+0

안녕하세요.이 목적과 배열 복사본을 위해 스레드를 사용하지 않았습니다. 나는 XML 파일을 파싱하기 위해 JDOM을 사용하고 있으며 구현을 위해 ArrayList를 사용한다고 생각한다. 문제가 될 수 있습니까? 메모리 누출 가능성이 있습니까? – Amit

0

많은 양의 메모리를 차지하는 파일과 DOM에 관한 두 번째 요점이 있습니다. 나는 또한 이것을 볼 때 궁금합니다 :

ERROR [JobRunShell]: Job updateVendorData.quoteUpdate threw an unhandled Exception: 
    java.lang.OutOfMemoryError: Java heap space 
    at java.util.Arrays.copyOfRange(Arrays.java:3210) 

그게 뭐하는거야? 나는 당신의 코드에서 계속 진행되고있는 또 다른 나쁜 점이 있는지 궁금합니다.

멀리까지 읽는다면 파일과 DOM을 성공적으로 읽고 데이터베이스에 쓰기 시작한 것입니다. 파일 메모리는 이미 다시 확보되어야합니다.

나는 무엇이 진행되고 있는지 알 수 있도록 VisualGC을 사용하여 메모리를 보는 것이 좋습니다.

+0

그 복사는 StringBuffer의 내부입니다. – BalusC

+0

안녕하세요, duffy, 답장을 보내 주셔서 감사합니다. JDOM이 내부적으로이 복사를 구현할 수 있습니까? 항상 응용 프로그램의 프로파일 링을 활성화했으며 GC가 실행 된 후에도 존재하는 두 개의 클래스가 있습니다. 이들은 org.postgresql.jdbc4.Jdbc4PrepareStatement 및 org.postgresql.jdbc4.Jdbc4ResultSet입니다. 응용 프로그램에서 메모리 누수가 발생할 수 있습니까? – Amit

+0

수 있습니다. 코드 없이는 말할 수 없지만 제대로 닫지 않으면 리소스가 누출되어 슬픔을 겪을 수 있습니다. – duffymo

2

구문 분석 XML은 상당히 비싼 작업입니다. 평균 DOM 파서는 이미 5 개의 시간의 XML 문서가 필요합니다. 이 사실도 고려해야합니다. XML 파서의 메모리 부족을 초래 한 다른 메모리 누수가 없도록하려면 프로파일 러를 실행해야합니다. 더 많은 메모리를주고 사용 가능한 메모리를 두 배로 늘리십시오. 원인을 찾아 내고 누설을 고쳤다면 "기본"메모리로 돌아가 다시 테스트 할 수 있습니다. 또는 누수가 전혀 없다는 뜻이라면, 기본값보다 조금 더 많은 메모리를 할당하면됩니다.

VTD-XML (homepage here, benchmarks here)과 같이 메모리 효율적인 XML 파서를 대신 사용할 수도 있습니다.

1

최대 힙 크기를 더 크게 설정하여 문제가 계속 발생하는지 확인 했습니까? 전혀 누출이 없을 수도 있습니다. 그것은 단지 기본 힙 크기 (Windows의 경우 64m)가이 특정 프로세스에 충분하지 않을 수도 있습니다.

나는 거의 항상 Tomcat을 기본값으로 사용하는 것보다 Tomcat을 많이 사용하고 있거나 메모리 부족 문제가 발생하는 응용 프로그램을 제공해야한다고 생각합니다. 메모리 설정을 조정하는 데 도움이 필요하면 this question을보십시오.

+0

안녕하세요 제이슨, 답장을 보내 주셔서 감사합니다. 나는 힙 크기를 늘렸고 응용 프로그램은 정상적으로 작동했습니다. 애플리케이션 프로파일 링을 설정하고 프로세스가 완료된 후 가비지 컬렉터에 의해 할당 해제되지 않은 라이브 할당 객체 2 가지를 찾을 수 있습니다. 이들은 org.postgresql.jdbc4.Jdbc4PrepareStatement 및 org.postgresql.jdbc4.Jdbc4ResultSet입니다. 응용 프로그램에서 메모리 누수가 발생할 수 있습니까? – Amit

+0

JDBC 객체가 올바르게 닫히지 않았 음을 나타내는 것일 수 있습니다. JDBC 호출을 직접하고 있습니까? 아니면 JDBC 호출을 감싸기 위해 Spring과 같은 프레임 워크를 사용하고 있습니까? JDBC를 직접 호출하는 경우, ResultSet, Statement, PreparedStatement 및 Connection 객체의 사용을 마쳤 으면 finally 블록의 close() 메소드를 호출해야합니다. –

+0

내 능력을 최대한 발휘하여 내가 연 모든 연결을 닫았지만 문제가 여전히 존재한다는 사실을 염두에 두었습니다. 이걸 가지고 나를 도울 수있는 방법이 있니? – Amit

0

다음과 같이 응용 프로그램을 실행할 수 있습니다. -XX : + HeapDumpOnOutOfMemoryError. 이로 인해 JVM은 메모리 부족시 힙 덤프를 생성합니다. 다음과 같은 것을 사용할 수 있습니다 : MAT 또는 JHAT. 생성 된 힙 덤프에 일식 메모리 분석기 도구 (MAT)를 사용하는 것이 좋습니다. http://www.eclipse.org/mat/

물론이 작업을 수행하기 위해 어떤 객체가 매달려 있는지에 대한 아이디어가 필요합니다 유용하다. DOM 개체? XML 문서의 이전로드에서 가져온 리소스? 데이터베이스 연결? MAT는 가비지 수집되어야한다고 의심되는 객체로부터 루트 객체에 대한 참조를 다시 추적 할 수있게합니다.

9

JVM의 RAM 할당을 늘리십시오. 도움이 될 것입니다.

  • 자바 -> 설치된 JRE를
  • 을 선택하십시오 일식에 대한

    수정 : - - (> 환경 설정 이클립스의 Mac에서)> 환경 설정

    1. 윈도우를 다음과 같이 일식 우선이를 구성 할 수 있습니다 JRE를 선택하고 -Xmx1024M의 기본 VM 인수 필드 유형에서 편집
    2. 을 클릭하십시오. (또는 귀하의 메모리 환경 설정, 1 램 램에 대한 1024)
    3. 완료 또는 확인을 클릭하십시오.
  • +1

    고맙습니다. –

    2

    Tomcat JVM의 PermGenSpace에 더 많은 공간을 할당해야합니다.

    이는 JVM 인수와 함께 할 수

    : 당신은 기본적으로 -XX:MaxPermSize=128m

    의 PermGen 공간은 64M (그리고 당신이 당신의 클래스 패스에 항아리의 많은 (클래스) 그래서 만약이 모든 컴파일 된 클래스가 포함되어 있습니다 실제로이 공간을 채울 수 있습니다.) 보조 노트에

    , 당신은 JVisualVM와 PermGen 공간의 크기를 모니터링 할 수 있습니다 그리고 당신은 당신의 JVM을위한 램 할당을 늘려보십시오 YourKit Java Profiler

    3

    와 내용을 검사 할 수 있습니다. 도움이 될 것입니다. 일식에 대한

    수정 :

    윈도우 다음과 같이 일식 우선이를 구성 할 수 있습니다 -> 환경 설정 (Mac에서의 이클립스 -> 환경 설정) 자바 -> 설치된 JRE를은 JRE를 선택하고 기본에서 편집을 클릭합니다 VM 인수 필드 유형은 -Xms256m -Xmx512m -XX : MaxPermSize = 512m -XX : PermSize = 128m입니다. (또는 귀하의 메모리 환경 설정, 램 1gb에 대한 1024) 완료 또는 확인을 클릭하십시오.