メンテナンス作業をしているWindowsサービスがあります。最近では、Luceneを使用していくつかの検索結果を事前に計算しようとする仕事を追加し、その後OutOfMemory(OOM)例外をスローし始めました。Windowsサービスで.NETのOutOfMemoryExceptionが発生する原因は何ですか?
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は数時間運転しても表示されます。また、例外が捕捉され、サービスは引き続き実行されます。
Luceneキャッシュ(FieldCache)は、オープンセグメントリーダーに基づく弱い参照を使用します。キャッシュエントリは、それぞれのセグメントリーダーが閉じられるまでガベージコレクションされません。 – sisve
@Simon Svensson - 読者は、各バッチの後に非常に短く(4〜5百の検索)終了します。 –