7

Tomcat で Java Web アプリケーションを実行しています。アプリケーションは、Quartz フレームワークを使用して、cron ジョブを定期的にスケジュールします。この cron ジョブには、JDOM API を使用して実行している 4 MB 以上の xml ファイルの解析が含まれます。xml ファイルには、解析対象の約 3600 のノードが含まれており、その結果、DB で更新されるデータが順次実行されます。
ファイルのほぼ半分を解析した後、アプリケーションがメモリ不足の例外をスローします。同じスタック トレースは次のとおりです。

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 です。

ありがとう、アミット

4

9 に答える 9

10

JVM の RAM 割り当てを増やしてみてください。それは役立つはずです。

Eclipse の修正: 次のように、Eclipse 設定でこれを構成できます。

  1. Windows -> 設定 (Mac の場合: eclipse -> 設定)
  2. Java -> インストール済みの JRE
  3. JRE を選択し、[編集] をクリックします。
  4. -Xmx1024M のデフォルトの VM 引数フィールド タイプ。(またはメモリの好み、1 GBのRAMの場合は1024)
  5. [完了] または [OK] をクリックします。
于 2013-01-09T05:53:15.787 に答える
5

DOM を使用して XML ファイルを解析するたびに、ファイル全体をメモリにロードし、DOM インフラストラクチャはそれを処理するためにほぼ同じサイズを使用するため、ファイル サイズの約 2 倍のメモリを消費します。

イベントベースのパーサーである SAX を使用する必要があります。これは最初は理解するのが難しいかもしれませんが、現在の解析ノードをメモリに保持するだけなので、メモリ効率が非常に高くなります。

Java にはStAXなどの SAX 実装がいくつかあるようです。

于 2009-11-30T09:22:52.303 に答える
3

XML の解析は、かなりコストのかかる作業です。平均的な DOM パーサーは、XML ドキュメントのサイズの少なくとも5倍のメモリ空間をすでに必要としています。この事実も考慮に入れる必要があります。XML パーサーのメモリ不足の原因となった別の場所でのメモリ リークがないことを確認するには、プロファイラーを実行する必要があります。メモリをすべて増やし、使用可能なメモリを 2 倍にしてプロファイルします。原因を突き止めてリークを修正したら、「デフォルト」メモリにフォールバックして再テストできます。または、リークの可能性が本当にない場合は、デフォルトよりも少し多くのメモリをすべて割り当てて、すべてが適合するようにします。

代わりに、よりメモリ効率の高い XML パーサーを使用することも検討できます。たとえば、VTD-XML (ホームページはこちらベンチマークはこちら)。

于 2009-11-30T11:31:43.843 に答える
3

JVM の RAM 割り当てを増やしてみてください。それは役立つはずです。

Eclipse の修正

これは、Eclipse の設定で次のように構成できます。

Windows -> 設定 (Mac の場合: Eclipse -> 設定) Java -> インストール済みの JRE

JRE を選択し、デフォルトの VM 引数フィールド タイプで [編集] をクリックします-Xms256m -Xmx512m -XX:MaxPermSize=512m -XX:PermSize=128m(またはメモリ設定、1 GB の RAM の場合は 1024 です)。[完了] または [OK] をクリックします。

于 2014-05-08T10:01:10.440 に答える
2

tomcat JVM の PermGenSpace により多くのスペースを割り当てる必要があります。

これは、JVM 引数を使用して実行できます。-XX:MaxPermSize=128m

デフォルトでは、PermGen スペースは 64M です (コンパイルされたすべてのクラスが含まれているため、クラスパスに多数の jar (クラス) がある場合は、実際にこのスペースを埋めることができます)。

ちなみに、JVisualVM を使用してPermGenスペースのサイズを監視でき、 YourKit Java Profilerを使用してその内容を検査することもできます。

于 2013-08-30T10:24:02.600 に答える
1

問題が引き続き発生するかどうかを確認するために、最大ヒープ サイズを大きく設定してみましたか? まったく漏れがない場合もあります。この特定のプロセスには、デフォルトのヒープ サイズ (Windows では 64m だと思います) が不十分である可能性があります。

ほとんどの場合、Tomcat を実行しているすべてのアプリケーションに、デフォルトよりも多くのヒープおよび perm gen スペースを与える必要があることがわかりました。そうしないと、メモリ不足の問題が発生します。メモリ設定の調整についてサポートが必要な場合は、この質問をご覧ください。

于 2009-11-30T11:54:30.430 に答える
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を使用してメモリを調べ、何が起こっているかを確認することをお勧めします。

于 2009-11-30T11:02:52.953 に答える
0

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

もちろん、これが役立つためには、どのオブジェクトがぶら下がっている可能性があるかについて、ある程度の考えが必要です。DOM オブジェクト? xml ドキュメントの以前のロードからのリソース? データベース接続?MAT を使用すると、ガベージ コレクションが必要であると思われるオブジェクトから、ルート オブジェクトへの参照をさかのぼって追跡できます。

于 2009-11-30T16:02:12.250 に答える
0

どこかに再帰的な配列のコピーがなく、誤ってそこに残されていませんか? おそらく別のスレッドで?

于 2009-11-30T09:23:58.693 に答える