Как использовать IDisposable для устранения утечек памяти - PullRequest
6 голосов
/ 24 июня 2010

У меня есть приложение .net, которое, похоже, имеет проблемы с утечкой памяти.Служба .net запускает около 100 МБ памяти, но при нагрузке она составляет около 400-500 МБ.Большинство моих классов не имеют неуправляемых ресурсов, и те, которые уже реализуют IDisposable.Таким образом, мой вопрос заключается в том, ударил ли IDisposable на моих уроках помощи?Концерн есть 8 различных услуг.Каждый построен с использованием SharpArch, NServiceBus, Windsor и NHibernate.Я чувствую, что в одном из них есть что-то, что вызывает проблемы.Меня беспокоит то, что общая память всех сервисов составляет от 3,2 до 3,6 гигабайт памяти из 4 гигов.Это еще не выбрасывает исключения OutOfMemory, но я хотел бы остановить это на проходе.Также я использовал dotTrace, который дает мне некоторую информацию, я просто не знаю, как действовать на эту информацию

Ответы [ 5 ]

17 голосов
/ 25 июня 2010

Моя первая задача - убедиться, что вы измеряете что-то важное. «Память» может означать много разных вещей. Существует огромная разница между нехваткой виртуальной памяти и нехваткой оперативной памяти. Существует огромная разница между проблемой производительности, вызванной перебивкой файла подкачки, и проблемой производительности, вызванной слишком большим давлением ГХ.

Если вы не понимаете, каковы взаимосвязи между ОЗУ, виртуальной памятью, рабочим набором и файлом подкачки, начните с чтения, пока не разберетесь во всем этом. То, как вы сформулировали вопрос, заставляет меня подозревать, что вы считаете, что виртуальная память и оперативная память - это одно и то же. Конечно, нет.

Я подозреваю, что вы делаете арифметику:

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

Этот силлогизм совершенно недействителен. Это силлогизм:

  • У меня восемь литров мороженого
  • У меня есть место для девяти четвертей мороженого в морозильной камере
  • Поэтому, если я получу еще две четверти мороженого, что-то растает.

когда на самом деле у вас есть целый склад холодного хранения размером с склад. Помните, ОЗУ - это просто удобный быстрый способ хранить вещи рядом с тем, где вам это нужно, например, в холодильнике. Если у вас есть больше вещей, которые нужно хранить, кого это волнует, если у вас не хватает места на месте? Вы всегда можете заскочить по соседству и поместить вещи, которые вы используете реже, в долгосрочную заморозку - файл подкачки. Это меньше удобно , но ничего не тает .

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

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

  • Не грозит ли какому-либо процессу использование более двух миллиардов байтов виртуальной памяти в 32-битной системе? Процесс получает только 2 ГБ виртуальной памяти (не ОЗУ, помните, виртуальная память не имеет ничего общего с ОЗУ: , поэтому его называют "виртуальным" - это не аппаратное обеспечение ) на win32, который адресуется код пользователя; Вы получите OOM, если попытаетесь использовать больше.

  • Не подвергается ли какой-либо процесс риску выделения огромного блока виртуальной памяти так, чтобы не было свободного смежного блока такого размера? Например, вы, вероятно, выделите десять миллионов байтов данных в одном массиве? Опять ООМ.

  • Это рабочий набор - то есть страницы виртуальной памяти процесса, которые * должны быть в оперативной памяти * из соображений производительности - всех процессов, меньших, чем объем оперативной памяти имеется в наличии? Если нет, то скоро вы получите молот, но не OOM.

  • Является ли ваш файл подкачки достаточно большим, чтобы обрабатывать страницы виртуальной памяти, которые могут быть выгружены на диск, если объем оперативной памяти начнет сокращаться?

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

15 голосов
/ 24 июня 2010

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

ПервыйПроблема в том, что вы не знаете, почему вы протекаете.Управляемые приложения обычно имеют утечку по одной из следующих причин:

  1. Неправильное удаление неуправляемых ресурсов
  2. Удержание больших графов объектов управляемых объектов

Учитываяинформация в вашем вопросе это почти наверняка # 2, что вызывает проблему.Вам понадобится профилировщик или windbg, чтобы сообщить вам, что такое настоящая утечка и какие корневые объекты ее вызывают.

Вот отличная статья Рико, с которой можно начать

5 голосов
/ 24 июня 2010

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

Имейте в виду, что сборщик мусора не обязательно освобождает память до тех пор, пока в этом нет необходимости, поэтому не исключено, что он может выделять 400-500 Мб выделенных ресурсов.Момент, в котором я был бы обеспокоен, был бы, когда после [вставьте разумный период времени здесь использования] он подкрался еще больше и достиг 1 ГБ, даже при том, что он не был под каким-либо более высоким уровнем нагрузки.

4 голосов
/ 24 июня 2010

Короткий ответ: Нет.

Более длинный ответ: Нееееееет.

Я думаю, вы уже знали это - если бы вы этого не делали, вы бы не "ударили" ID, доступным для занятийэто действительно нужно - IDisposable не имеет ничего общего с GC.Единственное, что действительно имеет здесь значение, это то, что если вы без надобности добавили Finalizer (~ classname) на свои объекты - это приведет к тому, что они будут скопированы в однопоточную очередь финализатора до того, как они получат GC'd, независимо от того, содержат ли они неуправляемые ресурсыили нет.

2 голосов
/ 25 июня 2010

Мера, мера, мера

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

Вы можете получить грубое представление, добавив несколько счетчиков perfmon для «частных байтов, байтов во всех кучах, байтов в куче больших объектов, поколения 1, поколения 2» и так далее.

Если вы решите, что используете слишком много управляемой памяти. Вы можете еще больше сократить использование, используя такой инструмент, как .Net memory profiler или очень гибкий, но windbg + sos

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

Маловероятно, что решение будет разбрызгиваться по всему.

...