В чем причина OutOfMemoryException в .NET в службе Windows при большой нагрузке? - PullRequest
1 голос
/ 22 января 2011

У меня есть служба Windows, которая выполняет некоторые работы по обслуживанию. Недавно мы добавили задание, которое пытается предварительно рассчитать какой-либо результат поиска с использованием Lucene , и с тех пор оно начало выдавать исключения OutOfMemory (OOM).

Некоторые подробности, которые я получил от WinDbg и SOS :

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 МБ (выделенный сегмент по умолчанию). Массив байтов, int и 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

Единственная идея, о которой я узнал, состоит в том, что исключение вызвано фрагментацией памяти. К сожалению, нет ответа на вопрос, почему память не сжимается.

Мы не прикрепляем никаких объектов, и кажется, что Lucene тоже не делает этого, хотя команда! Gcroot возвращает для некоторых объектов следующий результат:

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

Система: Windows Server 2008 R2, 32-битная
Всего передано байтов: ~ 950 МБ
Всего зарезервированных байтов: ~ 1 666 МБ (цифры взяты из системного монитора)

Средство поиска индекса и, следовательно, соответствующее средство чтения индекса регулярно закрываются после выполнения короткого пакета. После этого планируется новая партия, и работа продолжается. ООМ появляется через пару часов работы. Также возникает исключение, и служба продолжает работать.

1 Ответ

1 голос
/ 24 февраля 2011

Не было никакой утечки, но из-за высокой загрузки ЦП и памяти GC выдал ловкие исключения System.OutOfMemoryException (OOM).Поэтому с одной стороны процесс продолжал работать, а с другой стороны индекс не обновлялся.

По крайней мере, мне удалось как-то снизить нагрузку на память, и теперь система работает нормально.

Как указал Саймон Свенссон , сборщик мусора не собирает данные, если читатели все еще открыты, поэтому я решил проверить, как код работает с читателями.Оказалось, что было довольно много ненужных мест, где индекс был открыт.Если открыть индекс в одном месте и отправить его в качестве параметра, проблема исчезнет.

...