Подтвердить что ты не робот

.Net 4 Утечки MemoryCache с одновременной сборкой мусора

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

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

Был ли какой-то поиск в googling и stackoverflow, загружен и прикреплен CLRProfiler, и wham: выселения везде! Память оставалась в разумных пределах, основываясь на ограничении размера памяти, которое я установил. Вновь отменил его в режиме отладки, никаких выселений. CLRProfiler снова, выселения.

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

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

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


Обновление 1

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


Обновление 2

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

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

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

Ответ 4

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