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

Утечки памяти С#

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

4b9b3361

Ответ 1

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

В С# это некоторые распространенные утечки памяти:

  • Не удалять прослушиватели событий. Любой прослушиватель событий, созданный с помощью анонимного метода или выражения лямбда, который ссылается на внешний объект, сохранит эти объекты в живых. Не забудьте удалить прослушиватели событий, когда они больше не используются.
  • Сохранение связей базы данных или наборов результатов открывается, когда они не используются. Не забудьте вызвать Dispose() для всех объектов IDisposable. Используйте инструкцию using.
  • Вызов функций C с использованием p/Invoke, которые выделяют память, которую вы никогда не выпускаете.

Ответ 2

Традиционная утечка памяти происходит, когда вы выделяете память, а потом как-то "забываете" ее освободить. В старом коде C++ это означает вызов new без соответствующего delete. В Си это означало вызов alloc()/malloc() без соответствующего free().

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

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

Ответ 3

Очень хорошее чтение Все думают о сборке мусора неправильным образом.

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

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

Я очень рекомендую статью Раймонда Чена, связанную выше, очень хорошо освещает.

Ответ 4

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

Для управляемого кода сборщик мусора отслеживает ссылки на объекты, созданные приложением. В большинстве случаев среда CLR будет обрабатывать распределение и освобождение памяти прозрачно и разумно от имени выполняемого процесса. Однако разработчикам .NET по-прежнему необходимо учитывать управление ресурсами, поскольку есть еще ситуации, в которых память может протекать, несмотря на работу сборщика мусора.

Рассмотрим следующий код:

Widget widget = new Widget();

Вышеприведенная строка кода создает новый экземпляр класса Widget, а поле виджета назначается ссылка на этот объект. GC отслеживает ссылки, связанные с каждым объектом, и освобождает память объектов, для которых нет сильных ссылок.

Стоит отметить, что сборка мусора CLR будет собирать только управляемые объекты,.NET-код может и часто использует неуправляемые ресурсы, которые невозможно автоматически собирать мусор.

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

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

public void ManagedObject : IDisposable
{
    //A handle to some native resource.
    int* handle;

    public ManagedObject()
    {
        //AllocateHandle is a native method called via P/Invoke.
        handle = AllocateHandle();
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if (disposing)
        {
            //deal with managed resources here
            FreeHandle(handle);
        }
    }

    ~ManagedType()
    {
        Dispose(false);
    }
}

Параметр disposing является ложным при вызове из финализатора. Это делается для предотвращения использования управляемых ресурсов из финализатора, поскольку управляемые ссылки должны считаться недействительными на этом этапе.

Обратите внимание, что метод Dispose() вызывает GC.SuppressFinalize(this), который предотвращает запуск финализатора для этого экземпляра. Это делается из-за того, что ресурсы, которые были бы освобождены в финализаторе, были освобождены в вызове Dispose, делая ненужным вызов филаризатора.

Клиентский код, который использует классы, которые обрабатывают неуправляемые ресурсы (или любой класс, который реализует IDisposable), должен делать это в блоке using, чтобы гарантировать, что вызывается IDisposable.Dispose, когда доступ к ресурсу больше не нужен это позаботится об управляемых и неуправляемых ресурсах, а в случае вышеприведенного примера убедитесь, что очень дорогостоящий вызов финализатора не выполнен.

Аплодисменты для моей бессвязности. Я сейчас остановлюсь.

Ответ 5

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

Ответ 6

"Утечка памяти" должна быть определена как "память, которая используется, когда вы считаете, что ее не следует использовать", чтобы применить к сборщикам мусора или времени выполнения как С#/Java.

Традиционно "утечка памяти" определяется как память, которая не была должным образом освобождена (см. ссылку на wikipedia в других ответах), которая, как правило, не возникает для среды сбора мусора. Обратите внимание, что из-за проблем со временем выполнения даже собранные на мусорах языки могут утечки памяти, то есть даже если JavaScript является языком сбора мусора, было легко утечка большого количества объектов JavaScript в среду выполнения JavaScript Internet Explorer.