Как использовать IDisposable для фиксации утечек памяти

У меня есть приложение .NET, которое, кажется, имеет проблему (проблемы) утечки памяти. Услуги .NET начинают приблизительно 100 МБ памяти, но при загрузке это совершает нападки вокруг 400-500MB. Большинство моих классов не имеет неуправляемых ресурсов и тех, которые действительно уже реализуют IDisposable. Таким образом, мой вопрос, был бы, хлопая IDisposable на моей справке классов?

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

6
задан Kevin Up 24 June 2010 в 18:35
поделиться

5 ответов

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

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

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

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

Этот силлогизм полностью неверен.Вот силлогизм:

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

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

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

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

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

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

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

  • Достаточно ли велик ваш файл подкачки, чтобы обрабатывать страницы виртуальной памяти, которые могут быть выгружены на диск, если ОЗУ начинает не хватать?

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

17
ответ дан 8 December 2019 в 02:14
поделиться

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

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

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

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

Вот отличная статья Рико для начала

15
ответ дан 8 December 2019 в 02:14
поделиться

Ответ: почти наверняка нет. Вы проверили, действительно ли вы держите память, которую не должны держать, с помощью профилирования вашего сервиса?

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

5
ответ дан 8 December 2019 в 02:14
поделиться

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

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

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

4
ответ дан 8 December 2019 в 02:14
поделиться

Измерять, измерять, измерять

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

Вы можете получить приблизительное представление, добавив несколько счетчиков perfmon на "private bytes, bytes in all heaps, bytes in the large object heap, gen 1, gen 2" и так далее.

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

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

Очень маловероятно, что решение заключается в том, чтобы посыпать все IDisposable.

2
ответ дан 8 December 2019 в 02:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: