Утечка памяти .Net 4 с одновременной сборкой мусора - PullRequest
37 голосов
/ 14 апреля 2011

Я использую новую MemoryCache в .Net 4 с максимальным пределом размера кэша в МБ (я тестировал его установленным от 10 до 200 МБ, в системах с объемом памяти от 1,75 до 8 ГБ). ). Я не устанавливаю никакого истечения времени для объектов, так как я использую кеш просто как высокопроизводительный диск, и пока есть место, я хочу его использовать. К моему удивлению, кеш отказывался выселять какие-либо объекты, до такой степени, что я получил бы SystemOutOfMemory исключения .

Я запустил perfmon , подключил мое приложение к .Net CLR Memory\#Bytes In All Heaps, .Net Memory Cache 4.0 и Process\Private Bytes - действительно, потребление памяти вышло из-под контроля, и записи кэша не регистрировались .

Некоторые гуглили и стек переполнения , скачали и прикрепили CLRProfiler и wham : выселения повсюду! Память оставалась в разумных пределах, основываясь на установленном мною ограниченном объеме памяти. Запустил его снова в режиме отладки, никаких выселений. CLRProfiler снова, выселения.

Наконец-то я заметил, что профилировщик заставил приложение работать без одновременной сборки мусора (также см. Полезный ТАК вопрос одновременной сборки мусора ). Я выключил его в своем app.config и, конечно же, выселений!

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

Так кто-нибудь еще видел это? Я хотел бы получить некоторые другие впечатления, и, возможно, более образованные идеи.


Обновление 1

Я воспроизвел проблему в одном методе: похоже, что кэш должен записываться параллельно, чтобы не происходило его вытеснение (в режиме одновременного сбора мусора). Если есть какой-то интерес, я выложу тестовый код в публичный репозиторий. Я определенно добираюсь до глубокого конца пула CLR / GC / MemoryCache, и я думаю, что забыл свои сообщения ...


Обновление 2

Я опубликовал тестовый код на CodePlex , чтобы воспроизвести проблему. Также, возможно, представляет интерес исходный производственный код, выполняемый в Azure в качестве рабочей роли. Интересно, что изменение параметра параллелизма GC в app.config роли не имеет никакого эффекта. Возможно, Azure переопределяет настройки GC так же, как ASP.NET? Кроме того, выполнение тестового кода в WPF против консольного приложения приведет к несколько иным результатам выселения.

Ответы [ 4 ]

8 голосов
/ 14 апреля 2011

Вы можете «форсировать» сборку мусора сразу после проблемного метода и посмотреть, воспроизводится ли проблема, выполнив:

System.Threading.Thread.Sleep(200);
GC.Collect();
GC.WaitForPendingFinalizers();

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

4 голосов
/ 14 апреля 2011

Сборка мусора Stop-the-world основана на определении, существует ли сильная живая ссылка на объект в момент остановки мира.Параллельная сборка мусора обычно определяет, существует ли сильная живая ссылка на объект с какого-то определенного времени в прошлом.Моя гипотеза заключается в том, что многие сильные ссылки на объекты, содержащиеся в WeakReferences, создаются и удаляются индивидуально.Если сборщик мусора «останови мир» запускается между временем создания определенного объекта и временем его отбрасывания, этот конкретный объект будет поддерживаться в живых, а ранее удаленные объекты - нет.Напротив, одновременный сборщик мусора может не обнаружить, что все сильные ссылки на объект были отброшены, пока не пройдет определенное количество времени без каких-либо сильных ссылок на создаваемый объект.

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

2 голосов
/ 20 мая 2011

Я нашел эту запись во время поиска похожей темы, и я сосредоточился на вашем исключении Out of Memory.

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

Вы помещаете "использованные" объекты в кеш или клоны "использованных" объектов в кеш? Если вы поместите клон в кеш, то «используемый» объект, который может ссылаться на другие объекты, может быть собран мусором.

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

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

0 голосов
/ 23 августа 2016

MemoryCache определенно имеет некоторые проблемы.Он потреблял 160 Мб памяти на моем сервере asp.net, просто изменился на простой список и добавил дополнительную логику для получения той же функциональности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...