Как узнать, собираюсь ли я получить OutOfMemoryException?

У меня есть программа, которая обрабатывает большие объемы данных и может кэшировать большую часть ее для повторного использования с последующими записями в памяти. Чем больше я кешу, тем быстрее он работает. Но если я кешу слишком много, бум, начните заново, и это займет намного больше времени!

Я не слишком успешно пытался сделать что-либо после возникновения исключения - я не могу получить достаточно памяти, чтобы что-либо сделать.

Также я попытался выделить огромный объект, а затем отменил его сразу, с несогласованными результатами. Может быть, я делаю что-то не так?

Во всяком случае, то, что я застрял, - это просто установить жестко определенный предел для # кэшированных объектов, которые, по опыту, кажутся достаточно низкими. Любые лучшие идеи? спасибо.

изменить после ответа

Следующий код, похоже, делает именно то, что я хочу:

Loop 
    Dim memFailPoint As MemoryFailPoint = Nothing
    Try
        memFailPoint = New MemoryFailPoint( mysize) ''// size of MB of several objects I'm about to add to cache 
        memFailPoint.Dispose()
    Catch ex As InsufficientMemoryException
        ''// dump the oldest items here
    End Try
   ''// do work
next loop.

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

Ответ 1

Вы можете использовать MemoryFailPoint, чтобы проверить доступную память до выделения.

Ответ 2

Возможно, вам придется подумать о своей стратегии выпуска для кэшированных объектов. Невозможно, чтобы вы могли удерживать их всех навсегда, поэтому вам нужно придумать таймфрейм истечения срока действия и удалить из памяти старые кешированные объекты. Должно быть возможно узнать, сколько памяти осталось и использовать это как часть вашей стратегии, но одно можно сказать, старые объекты должны идти.

Ответ 3

Существует ряд показателей, которые вы можете использовать для отслеживания того, сколько памяти использует ваш процесс:

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

Однако вы можете использовать эти значения как показатель того, сколько памяти использует этот процесс, и, следовательно, следует ли думать об удалении объектов из вашего кеша.

Обновление: Также важно убедиться, что вы понимаете различие между виртуальной памятью и физической памятью - если ваш файл страницы не отключен (очень маловероятно), причина OutOfMemoryException будет вызвана отсутствием/фрагментацией виртуального адресного пространства.

Ответ 4

Если вы реализуете свой кеш с помощью WeakRerefence (http://msdn.microsoft.com/en-us/library/system.weakreference.aspx), который оставит кешированные объекты по-прежнему пригодными для сбора мусора в ситуациях, когда вы в противном случае может вызвать исключение OutOfMemory.

Это альтернатива кешу фиксированного размера, но потенциально может возникнуть проблема чрезмерной агрессивности при очистке кеша при сбое GC.

Вы можете подумать о гибридном подходе, где есть (настраиваемое) фиксированное количество неудобных референций в cahce, но вы позволяете ему расти дополнительно со слабыми референциями. Или это может быть излишним.

Ответ 5

Если вы используете только управляемые ресурсы, вы можете использовать метод GC.GetTotalMemory и сравнить результаты с максимально допустимой памятью для процесса на вашей архитектуре.

Более продвинутое решение (я думаю, что SQL Server удается фактически адаптироваться к доступной памяти) заключается в использовании CLR Hosting APIs

интерфейс позволяет CLR информировать хозяина о последствиях сбой при определенном распределении

что будет означать фактическое удаление некоторых объектов из кеша и повторение попыток.

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

Ответ 6

Простой ответ... зная, каков ваш предел памяти.

Чем ближе вы достигнете этого предела, тем больше вы хотите получить исключение OutOfMemoryException.

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

Память - это ресурс, который вы можете использовать; у него есть ограничения, и у него также есть некоторые соглашения и правила для вас, чтобы хорошо использовать этот ресурс.

Я считаю, что вы делаете настройку хорошего лимита, жестко закодированного или настраиваемого, кажется лучшим вашим выбором.