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

.NET. Свободное использование памяти (как предотвратить общую запись/выпуск памяти в ОС)

В настоящее время я работаю над веб-сайтом, который широко использует кэшированные данные, чтобы избежать обращений. При запуске мы получаем "большой" график (сотни тысяч разных объектов). Эти объекты извлекаются по WCF и десериализуются (мы используем буферы протокола для сериализации) Я использую профилировщик памяти redgate для отладки памяти (память, похоже, не соответствует тому, сколько памяти нам нужно "после", мы закончили инициализацию и закончили с этим отчетом

Global Report

Теперь, что мы можем собрать из этого отчета, является то, что:

1) Большая часть выделенной памяти .NET бесплатна (возможно, она была по праву выделена во время десериализации, но теперь, когда она бесплатна, я бы хотел, чтобы она вернулась в ОС)

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

3) Я не знаю, почему пространство фрагментировано, потому что, когда я смотрю на кучу большого объекта, всего 30 экземпляров, 15 объектов [] напрямую привязаны к GC и совершенно не связаны со мной, 1 - это char массив также прикреплен непосредственно к GC Heap, остальные 15 являются моими, но не являются причиной этого, поскольку я получаю тот же отчет, если я прокомментирую их в коде.

Итак, мой вопрос: что я могу сделать, чтобы пойти дальше? Я не уверен, что искать в отладке/инструментах, так как кажется, что моя память фрагментирована, но не мной, а огромное количество свободных пространств выделяется .net, который я не могу освободить.

Также, пожалуйста, убедитесь, что вы хорошо поняли вопрос перед ответом, я не ищу способ освободить память в .net(GC.Collect), но освободить свободную память, которая уже свободна в .net, в систему а также для дефрагментации памяти.

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

Спасибо за вашу помощь!

Несколько заметок, которые я забыл: 1) Проект является веб-сайтом .net 2.0, я получаю те же результаты, что и он в пуле .net 4, idem, если я запустил его в пуле .net 4 и преобразовал его в .net 4 и перекомпилировал.

2) Это результаты сборки релиза, поэтому отладка сборки не может быть проблемой.

3) И это, вероятно, очень важно, я не получаю эти проблемы вообще на сервере webdev, только в IIS, в webdev я получаю потребление памяти довольно близко к моему фактическому потреблению (а больше, но не 5- 10X больше!)

4b9b3361

Ответ 1

Объекты, выделенные на кучу больших объектов (объекты >= 85 000 байт, обычно массивы) не уплотняются сборщиком мусора. Microsoft решила, что стоимость перемещения этих объектов будет слишком высокой.

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

http://msdn.microsoft.com/en-us/magazine/cc534993.aspx

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

Ответ 2

Я знаю, что это не тот ответ, который вы хотели бы услышать, но вы не можете принудительно освободить память обратно в ОС. Однако по какой причине вы хотите это сделать?.NET освободит свою кучу обратно в ОС, как только вы начнете работать с низкой физической памятью. Но если имеется достаточное количество свободной физической памяти,.NET будет сохранять свою кучу, чтобы быстрее распределять объекты быстрее. Если вы действительно хотели заставить .NET выпустить свою кучу обратно в ОС, я полагаю, вы могли бы написать программу на C, которая просто mallocs, пока не закончится память. Это должно привести к тому, что ОС сообщит .NET, чтобы освободить неиспользуемую часть кучи.

Лучше, чтобы неиспользуемая память была восстановлена ​​для .NET, так что ваше приложение будет иметь лучшую производительность распределения (поскольку среда выполнения знает, какая память свободна, а что нет, распределение может просто использовать свободную память без необходимости запуска ОС, чтобы получить больше памяти).

Сборщик мусора отвечает за дефрагментацию кучи. Каждый раз так часто (обычно во время сборов) он перемещает объекты вокруг кучи, если это будет необходимо. (Вот почему С++/CLI имеет конструкцию pin_ptr для "закрепления" объектов).

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

Что касается вашего OutOfMemoryException, у меня нет хорошего ответа. Обычно я подозреваю, что ваш старый граф объектов не собирается (какой-то объект где-то держит ссылку на него, "утечка памяти" ). Но поскольку вы используете профилировщик, я не знаю тогда.

Ответ 3

Некоторое тестирование и некоторые С++ позже я нашел причину, по которой я получаю так много свободной памяти, из-за того, что IIS запускает CLR через VM Hoarding (предоставление DLL для создания экземпляра без VM Hoarding занимает столько же начальной памяти, но выпускает большую часть из них с течением времени, которое я ожидаю от поведения). Таким образом, это исправляет мою проблему с сообщенной памятью, однако я все равно получаю около 100 Мб свободной памяти, несмотря ни на что, и я все еще думаю, что это связано с фрагментацией и фрагментами, которые только выпущены сразу, потому что профилировщик все еще сообщает о фрагментации памяти. Поэтому, не отмечая моего собственного ответа в качестве ответа в надежде, кто-то может пролить свет на это или направить меня к инструментам, которые могут либо исправить это, либо помочь мне отладить основную причину.

Ответ 4

Интригует, что он работает по-разному на WebDevServer как на IIS...

Возможно ли, что IIS использует сборщик мусора сервера, а сервер WebDev - сборщик мусора рабочей станции? Метод сбора мусора может повлиять на фрагментацию. Вероятно, он будет установлен в файле aspnet.config. См.: http://support.microsoft.com/kb/911716

Ответ 5

Начиная с .NET 4.5.1 вы можете установить единовременный флаг для компактного LOH перед выдачей вызова GC собирать, т.е.

Runtime.GCSettings.LargeObjectHeapCompactionMode = System.Runtime.GCLargeObjectHeapCompactionMode.CompactOnce; GC.Collect();//Это приведет к уплотнению LOH (один раз).

Ответ 6

Если вы не нашли свой ответ, я думаю, что следующие подсказки помогут вам:

Вернемся к основам: мы иногда забываем, что объекты могут быть явно свободны, явно вызывать метод Dispose объектов (потому что вы не упомянули об этом, я полагаю, вы делаете "object = null" ).

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

В справке MSDN говорится об этом методе:

... В реализации Dispose нет выгоды от производительности метод для типов, которые используют только управляемые ресурсы (такие как массивы) потому что они автоматически возвращаются сборщиком мусора. использование метод Dispose в основном на управляемых объектах, которые используют собственные ресурсов и на COM-объекты, которые подвержены .NET. Framework....

Поскольку в нем говорится, что " они автоматически возвращаются сборщиком мусора", мы можем заключить, что при вызове метода происходит "освобождение" (Again Im, пытающееся только дать вам подсказки).

Кроме того, я нашел эту интересную статью (я полагаю... я ее полностью не читал): Сбор мусора: автоматическое управление памятью в Microsoft.NET Framework (http://msdn.microsoft.com/en-us/magazine/bb985010.aspx), в котором говорится следующее в разделе Принудительный объект для очистки:

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

Возможно, ответ лежит в этой статье, если вы внимательно прочитаете ее или просто продолжаете расследование в этом направлении.