2011-01-22 24 views
1

メンテナンス作業をしているWindowsサービスがあります。最近では、Luceneを使用していくつかの検索結果を事前に計算しようとする仕事を追加し、その後OutOfMemory(OOM)例外をスローし始めました。Windowsサービスで.NETのOutOfMemoryExceptionが発生する原因は何ですか?

私はWinDbgSOSから得たいくつかの詳細:!

0:034> !analyzeoom 
Managed OOM occured after GC#176014 (Requested to allocate 2621440 bytes) 
Reason: Low on memory during GC 
Detail: SOH: Failed to reserve memory (16777216 bytes) 

dumpheap -statコマンド結果(最後のもの)

65fe4944 81900  34614564 System.Byte[] 
65fe2938 76014  35904328 System.Int32[] 
65f96064  74  39988372 System.Int64[] 
65fdf9ac 3208118 150302932 System.String 
00265090  363 247694656  Free 
Total 9035539 objects 

そうそこに空きメモリがあるが、それは断片化されますと、すべての部分が16   MB(デフォルトの割り当てセグメント)より小さい。 バイト、整数、およびint64の配列はLucene Cacheによって保持されます。ソートを使用するクエリのためにキャッシュがアクティブになります。 Luceneキャッシュの実装はWeakReferenceHashMapに基づいているため、メモリー不足の場合はガーベッジコレクターでクリーンアップする必要があります。

Heapstatコマンド

0:034> !heapstat 
Heap    Gen0   Gen1   Gen2   LOH 
Heap0   1643476  2689484 526084512 196389976 

Free space:             Percentage 
Heap0    12   12 170262384  77432248SOH: 32% LOH: 39% 

ログファイルから例外ダンプは次のようになります。

Quartz.Core.ErrorLogger - Job (DEFAULT.precalculate-similar-index threw an exception. 
Quartz.SchedulerException: Job threw an unhandled exception. ---> System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown. 
    at Lucene.Net.Search.FieldCacheImpl.LongCache.CreateValue(IndexReader reader, Entry entryKey) in C:\Dev\Lucene.Net_2_9_2\src\Lucene.Net\Search\FieldCacheImpl.cs:line 685 
    at Lucene.Net.Search.FieldCacheImpl.Cache.Get(IndexReader reader, Entry key) in C:\Dev\Lucene.Net_2_9_2\src\Lucene.Net\Search\FieldCacheImpl.cs:line 240 
    at Lucene.Net.Search.FieldCacheImpl.GetLongs(IndexReader reader, String field, LongParser parser) in C:\Dev\Lucene.Net_2_9_2\src\Lucene.Net\Search\FieldCacheImpl.cs:line 639 
    at Lucene.Net.Search.FieldCacheImpl.LongCache.CreateValue(IndexReader reader, Entry entryKey) in C:\Dev\Lucene.Net_2_9_2\src\Lucene.Net\Search\FieldCacheImpl.cs:line 667 
    at Lucene.Net.Search.FieldCacheImpl.Cache.Get(IndexReader reader, Entry key) in C:\Dev\Lucene.Net_2_9_2\src\Lucene.Net\Search\FieldCacheImpl.cs:line 240 
    at Lucene.Net.Search.FieldCacheImpl.GetLongs(IndexReader reader, String field, LongParser parser) in C:\Dev\Lucene.Net_2_9_2\src\Lucene.Net\Search\FieldCacheImpl.cs:line 639 
    at Lucene.Net.Search.FieldComparator.LongComparator.SetNextReader(IndexReader reader, Int32 docBase) in C:\Dev\Lucene.Net_2_9_2\src\Lucene.Net\Search\FieldComparator.cs:line 481 

私が知ってまで得た唯一のアイデアは、例外がメモリの断片化によって引き起こされていることです。残念ながら、なぜメモリが圧縮されていないのかという疑問に対する答えはありません。

我々はすべてのオブジェクトを固定していない、いくつかのオブジェのためのgcrootコマンド戻り、次の結果がLuceneのは、どちらかないようです:!は

DOMAIN(0025D260):HANDLE(Pinned):1f13ec:Root: 02393250(System.Object[]) - from !gcroot 
ESP:16f2e4: sizeof(02393250) = 123436600 ( 0x75b7e38) bytes (System.Object[]) - size of the pinned arrays of objects 

は、System:Windows Server 2008 R2 32ビット
合計コミットバイト:〜950  メガバイト
合計予約バイト:〜1,666  メガバイト

インデックスサーチャー、したがって関連するインデックスリーダーが定期的に閉じている(数字は、パフォーマンスモニタから取られます)短いバッチが行われた後。その後、新しいバッチがスケジュールされ、作業が続行されます。 OOMは数時間運転しても表示されます。また、例外が捕捉され、サービスは引き続き実行されます。

+2

Luceneキャッシュ(FieldCache)は、オープンセグメントリーダーに基づく弱い参照を使用します。キャッシュエントリは、それぞれのセグメントリーダーが閉じられるまでガベージコレクションされません。 – sisve

+0

@Simon Svensson - 読者は、各バッチの後に非常に短く(4〜5百の検索)終了します。 –

答えて

0

リークはありませんでしたが、CPUとメモリの負荷が高いため、GCはSystem.OutOfMemoryException(OOM)例外を投げ捨てました。だから一方の側からプロセスは継続し、他方の側からはインデックスは更新されませんでした。

少なくとも私は何とかメモリの負担を軽減することができましたが、現在システムは正常に動作しています。

Simon Svensson指摘すると、GCは読者がまだ開いているかどうかを収集していないため、コードが読者をどのように扱っているかを確認することにしました。索引が開かれていた場所が比較的多いので、索引を開いて、それを必要とするすべてのメソッドにパラメータとして送信し、問題を解消しました。

関連する問題