2009-11-30 42 views
7

TomcatでJava Webアプリケーションを実行しています。このアプリケーションでは、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もクラッシュします。あなたは問題の診断に私を助けてくれますか?私も同じことをNetbeansでプロファイリングを有効にしているが、それもクラッシュしたようだ。私は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

こんにちはLorenzog、私はこの目的のために配列のコピーを使用していません。私はXMLファイルを解析するためにJDOMを使用しており、実装にはArrayListを使用していると思います。それは問題になることができますか?メモリリークの可能性はありますか? – Amit

0

私は、ファイルとDOMが大量のメモリを占めている点について、2番目のポイントになります。

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

こんにちはダフィー、あなたの返事をありがとう。 JDOMは内部的にこのコピーを実装できますか?私は常にアプリケーションのプロファイリングを有効にしており、GC実行後も存在する2つのクラスはorg.postgresql.jdbc4.Jdbc4PrepareStatementとorg.postgresql.jdbc4.Jdbc4ResultSetです。これらがアプリケーションのメモリリークを引き起こす可能性がありますか? – Amit

+0

可能性があります。コードなしでは伝えることはできませんが、これらを適切にクローズしていないと、リソースが漏れて悲しみを引き起こす可能性があります。 – duffymo

2

XMLの解析は、かなり高価な作業です。平均的なDOMパーサーは、すでにXML文書のサイズが大きいので、少なくとも5つの倍のメモリスペースが必要です。この事実も考慮する必要があります。 XMLパーザのメモリ不足の原因となったメモリリークがないようにするには、実際にプロファイラを実行する必要があります。すべてのメモリを増やし、使用可能なメモリを2倍にしてプロファイルします。原因を釘付けにしてリークを修正したら、単に「デフォルト」のメモリに戻って再テストすることができます。または、実際に漏れの手段がない場合は、デフォルトよりも少しだけ多くのメモリを与えて、すべてが合うようにします。

たとえば、VTD-XMLhomepage here,benchmarks here)のような、よりメモリ効率の良いXMLパーサーを使用することも考えられます。

1

最大ヒープサイズを大きく設定しても問題が解決しない場合は、漏れさえ全くないかもしれません。この特定のプロセスでは、デフォルトのヒープサイズ(Windowsでは64mと思う)が不十分である可能性があります。

私はほとんどの場合、Tomcatをデフォルトのものよりも多くのヒープとパーマネントスペースを実行しているアプリケーションに割り当てる必要があることがわかります。そうでないとメモリ不足に陥ります。メモリ設定を調整するのに助けが必要な場合は、this questionをご覧ください。

+0

こんにちはジェイソン、あなたの返信いただきありがとうございます。私はヒープサイズを増やし、アプリケーションは正常に動作しました。アプリケーションのプロファイリングを設定し、プロセスが完了した後、2種類のライブ割り当てオブジェクトがガベージコレクタによって割り当て解除されず、org.postgresql.jdbc4.Jdbc4PrepareStatementおよびorg.postgresql.jdbc4.Jdbc4ResultSetが見つかる可能性があります。これらがアプリケーションのメモリリークを引き起こす可能性がありますか? – Amit

+0

これは、JDBCオブジェクトが正しく終了していないことを示している可能性があります。あなたは自分でJDBCコールをやっているのですか、あるいはJDBCコールをラップするために春のようなフレームワークを使っていますか? JDBCを直接呼び出す場合は、ResultSet、Statement、PreparedStatement、およびConnectionオブジェクトの使用を終了したときにfinallyブロック内のclose()メソッドを必ず呼び出してください。 –

+0

最高の能力で、私は開いたすべての接続を閉じても問題は残っていることに気を付けました。あなたがこれで私を助けることができる方法はありますか? – Amit

0

-XX:+ HeapDumpOnOutOfMemoryErrorでアプリケーションを実行できます。これにより、メモリが不足したときにJVMがヒープダンプを生成します。どんなオブジェクトが保持されているかを見るには、MATやJHATのようなものを使うことができます。生成されたヒープダンプにEclipseメモリアナライザツール(MAT)を使用することをお勧めします。http://www.eclipse.org/mat/

もちろん、有用である。 DOMオブジェクト? XML文書の以前のロードからのリソース?データベース接続? MATでは、ガベージコレクションされているはずのオブジェクトから、ルートオブジェクトへの参照をトレースすることができます。

9

JVMのRAM割り当てを増やしてください。それは助けになるはずです。日食のための

修正:

  1. Windowsの次のようにあなたは日食の好みでこれを設定することができます - >環境設定(Mac上でその:日食 - >環境設定)
  2. のJava - >インストール済みのJRE
  3. を選択JREを選択し、デフォルトのVM引数フィールドの-Xmx1024Mにある
  4. をクリックします。 (またはあなたのメモリの好み、1グラムのRAMのための1024)
  5. 終了またはOKをクリックしてください。
+1

ありがとうございます –

2

Tomcat JVMのPermGenSpaceにさらに領域を割り当てる必要があります。

これは、JVM引数を指定して行うことができます

:あなたは、デフォルトでは-XX:MaxPermSize=128m

、PermGen空間は64Mです(そして、あなたのクラスパスにjarファイルの多く(クラス)を持っているので、もしそれが、すべてのコンパイル済みのクラスが含まれています実際にこのスペースを埋めるかもしれない)。サイドノートでは

、あなたはJVisualVMでPermGenスペースのサイズを監視することができますし、あなたもあなたのJVM用のRAMの割り当てを増やしてみてくださいYourKit Java Profiler

3

とその内容を検査することができます。それは助けになるはずです。日食のための

修正:

Windowsは、次のようにあなたは日食の好みでこれを設定することができます - >設定: - ジャワ(Mac上でその>好み日食は) - >インストール済みのJREは、デフォルトでJREを選択し、[編集]をクリックします-Xms256m -Xmx512m -XX:MaxPermSize = 512m -XX:PermSize = 128mのVM引数フィールドタイプ。 (またはメモリの設定、1GBのRAMの場合は1024)FinishまたはOKをクリックします。

関連する問題