Ошибка .NET 4 WCF

Я попал в проблему, когда мое приложение ASP.NET 4 MVC 2 + WCF использует большое количество памяти в приложении Windows 2008 64-bit во время нагрузочного тестирования, где оно будет использоваться почти через всю доступную память (8 ГБ) через несколько минут (у нас было мало рабочих процессов).

После профилирования с использованием ANTI Memory Profiler он показывал несколько интересных результатов:

  • Увеличение управляемой памяти .NET с 15 Мбайт до 40 МБ. Однако это объясняется механизмом кэширования, который мы выполняли в программе. Однако сама .NET выделяет выделение почти 180 МБ свободного пространства, что неожиданно.
  • Размер неуправляемой памяти значительно увеличивается до 120 МБ после того, как тестовый тест запускается примерно на 3 минуты (хотя наше приложение явно не использует какой-либо объект P/Invoke или COM. Однако мы использовали несколько COM + -объектов, которые после использования в блоке finally).
  • Память становится фрагментированной.
  • Оба элемента № 1 и 2 выше приводят к тому, что все приложение использует около 350 МБ сразу после теста нагрузки, работающего несколько минут, но если мы не остановим тест, он будет продолжать расти дальше.

Основываясь на элементе № 1 выше, я протестировал некоторое приложение для проверки того, связана ли проблема с нашим приложением или WCF. Приложение-тест просто загружает данные XML (около 300 КБ) в набор данных в многопоточном приложении. Когда логика хранится в программе EXE, приложение использует только 200 КБ (дополнительно 120 КБ с 40 КБ для неиспользуемой памяти) управляемую память из 24 МБ частных байтов после окончания (что приемлемо); , но когда логика размещается в WCF, приложение использует 66 МБ управляемой памяти (дополнительно 61 МБ от начала до 64 МБ свободной/неиспользуемой управляемой памяти). Таким образом, кажется, что WCF/ASP.NET - это тот, который сильно увеличивает память).

  • Почему .NET выделяет столько свободного места в куче?. Понятно, что свободное пространство может быть некоторым Gen 0/Gen 1/Gen 2, которое GC-ed во время моментального снимка памяти, но я не думайте, что приложение действительно использует столько памяти.
  • - нормальное поведение для WCF? Если да, любой способ изменить поведение, чтобы он использовал меньшую память?
  • Как найти неуправляемую утечку памяти, особенно, что я не использовал неуправляемый код явно?

Цените свой совет по вышеуказанному вопросу.

Спасибо заранее,

Вилли

Ответ 1

WCF использует временные буферы для обработки сообщений. То, что вы воспринимаете как утечку памяти, может быть временными буферами, которые еще не собраны.

Чтобы избежать создания новых буферов все время WCF использует BufferManager для повторного использования буферов, до предела, указанного maxBufferPoolSize (ссылка на элемент здесь), который по умолчанию составляет 512 КБ. Любые запросы, выходящие за пределы этого ограничения, создают новые буферы, которые никогда не используются повторно и должны быть собраны в мусор.

Другая опция для проверки - maxBufferSize, которая ограничивает максимальный размер буфера, который может быть возвращен BufferManager. Большие буферы не объединены и должны быть собраны в мусор. Если вы используете большие сообщения, вы можете уменьшить временные буферы, увеличив это свойство.

Попробуйте увеличить maxBufferPoolSize, чтобы узнать, можно ли уменьшить использование памяти. Я бы настоятельно советовал, хотя НЕ, чтобы это было максимально, потому что буферы из пула никогда не выпускаются до тех пор, пока не вернется домен приложения (т.е. Пул приложений). Период высокого трафика может привести к тому, что большая часть памяти будет использоваться и никогда не будет выпущена.

Ответ 2

Просто на догадку: подписываетесь на какие-либо статические события или события в долгоживущих объектах?

  • Объект, подписанный на статическое событие, будет жить вечно (или пока не будет подписан).
  • Объект, подписанный на событие объекта, будет жить в течение всего жизненного цикла этого объекта (или до тех пор, пока не будет подписан).

Итак, убедитесь, что вы старательно отменили подписку на события в любом из этих случаев.

Ответ 3

Что касается "неуправляемой утечки памяти", у меня был такой случай когда-то, и после некоторого копания он был провайдером ADO.NET - исправил это с обновленной версией: -)

Что касается остальных - попробуйте поместить это в конфигурацию:

<Configuration>
    <runtime>
        <gcServer enabled="true" />
    </runtime>
</Configuration>

Кроме этого нет ничего особенного в WCF IMHO... может быть утечка памяти, как в любом приложении .NET(например, обработчик событий и статические обработчики/объекты могут создавать утечки памяти, если не unsubsrcibed правильно)...