Почему .NET не имеет утечек памяти?

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

Я понимаю, что сама структура написана на С++, а С++ восприимчив к утечкам памяти.

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

Ответ 1

Здесь уже есть хорошие ответы, но я хочу обратиться к еще одному вопросу. Давайте посмотрим очень внимательно на ваш конкретный вопрос:


Я понимаю, что сама структура написана на С++, а С++ восприимчив к утечкам памяти.

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

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

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

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

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

Является ли базовая структура настолько хорошо написанной, что она абсолютно не имеет возможности утечки внутренней памяти?

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

Ответ 2

У .NET могут быть утечки памяти.

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

Тем не менее, много раз программисты не понимают, что объекты все еще имеют свисающие ссылки и не получают собранный мусор, вызывая утечку памяти.

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

Ответ 3

После просмотра документации Microsoft, в частности "" Идентификация утечек памяти в среде CLR", Microsoft делает выражение, что, пока вы не являетесь внедрение небезопасного кода в ваше приложение, чтобы не было утечки памяти

Теперь они также указывают на концепцию воспринятой утечки памяти или, как указывалось в комментариях, "утечка ресурсов", которая является использованием объекта, который имеет затяжные ссылки и не утилизируется должным образом. Это может произойти с объектами IO, наборами данных, элементами GUI и т.п. Это то, что я обычно приравниваю к "утечке памяти" при работе с .NET, но они не являются утечками в традиционном смысле.

Ответ 4

Из-за сбора мусора вы не можете иметь регулярные утечки памяти (помимо особых случаев, таких как небезопасный код и P/Invoke). Тем не менее, вы можете непреднамеренно сохранить ссылку навсегда, что эффективно утечки памяти.

изменить

Лучший пример, который я видел до настоящего времени, - это обработчик события + = ошибка.

изменить

См. ниже объяснение ошибки и условия, при которых она квалифицируется как настоящая утечка, а не почти настоящая утечка.

Ответ 5

Вот пример утечки памяти в .NET, которая не включает небезопасные /pinvoke и даже не включает обработчики событий.

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

class Message 
{
  public Message(int id, string text) { MessageId = id; Text = text; }
  public int MessageId { get; private set; }
  public string Text { get; private set; }
}

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

Итак, вы добавляете новое свойство...

class Message
{
  ...
  public Message PreviousMessage { get; private set; }
  ...
}

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

  Message lastMessageReceived;

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

Ответ 7

Я полагаю, что можно писать программное обеспечение, например. среда выполнения .NET(CLR), которая не утечка памяти, если вы достаточно осторожны. Но так как Microsoft время от времени выпускает обновления .NET Framework через Центр обновления Windows, я уверен, что в CLR иногда появляются ошибки.

Все программное обеспечение может утечки памяти.

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

Кроме того, я недавно столкнулся с возможной утечкой памяти в настройке .NET-COM interop. Компоненты COM используют подсчет ссылок, чтобы решить, когда они могут быть освобождены..NET добавляет еще один механизм подсчета ссылок, на который может влиять статический класс System.Runtime.InteropServices.Marshal.

В конце концов, вам все равно нужно быть осторожным в управлении ресурсами даже в .NET-программе.

Ответ 8

У вас могут быть проблемы с утечкой памяти в .NET-коде. Некоторые объекты, в некоторых случаях, сами root (хотя обычно это IDisposable). Неспособность вызвать Dispose() на объекте в этом случае абсолютно вызовет реальную утечку памяти стиля C/С++ с выделенным объектом, который у вас нет для ссылки.

В некоторых случаях некоторые классы таймера могут иметь такое поведение, как один пример.

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

Вот пример кода с помощью System.Threading.Timer.

public class Test
{
    static public int Main(string[] args)
    {
        MakeFoo();
        GC.Collect();
        GC.Collect();
        GC.Collect();
        System.Console.ReadKey();
        return 0;
    }

    private static void MakeFoo()
    {
        Leaker l = new Leaker();
    }
}

internal class Leaker
{
    private Timer t;
    public Leaker()
    {
        t = new Timer(callback);
        t.Change(1000, 0);
    }

    private void callback(object state)
    {
        System.Console.WriteLine("Still alive!");
        t.Change(1000, 0);
    }
}

Во многом как GlaDOS, объект Leaker будет бесконечно "все еще жив", но пути доступа нет объект (кроме внутреннего, и как объект может знать, когда он больше не ссылается?)

Ответ 9

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

Но .NET может иметь утечки памяти. утечки GDI, например, распространены среди приложений Windows Forms. Одно из приложений, которое я помогало регулярно развивать опыт. И когда сотрудники в офисе используют несколько экземпляров в течение всего дня, это не редкость для них, чтобы поразить 10 000 ограничений объекта GDI, присущих Windows.

Ответ 10

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

Ответ 11

Один из основных источников утечек памяти C/С++, который фактически не существует в .NET, заключается в том, чтобы освободить разделяемую память

Ниже приводится класс во главе класса Brad Abrams по проектированию библиотек классов .NET.

"Ну, в первую очередь, конечно, нет утечек памяти, верно? Нет? Есть еще утечки памяти? Ну, есть утечка памяти другого типа. Как насчет этого? утечка, которой мы не располагаем, в старом мире вы использовали для malloc некоторую память, а затем забыли сделать бесплатный или добавить ref и забыть сделать выпуск, или что бы ни пара была. И в новом мире сборщик мусора в конечном счете, владеет всей памятью, и сборщик мусора освободит этот материал, когда больше не будет ссылок. Но все еще могут быть утечки, правильно? Каковы утечки? Ну, если вы держите ссылку на этот объект живым, тогда сборщик мусора не может этого освободить. Так много раз, что происходит, вы думаете, что вы избавились от всего этого графика объектов, но все еще один парень держится за ним со ссылкой, а затем вы застряли. коллекционер не может освободить это, пока вы не отбросите все свои ссылки на него.

Другой, я думаю, большой вопрос. Отсутствие проблемы с памятью. Если вы прочитаете документацию по API WIN32, вы увидите, хорошо, я сначала распределяю эту структуру и передаю ее, а затем вы ее заполняете, а затем я освобождаю ее. Или я говорю вам размер, и вы его распределяете, а затем я освобождаю его позже или вы знаете, все эти дебаты происходят о том, кто владеет этой памятью и где ее предполагается освободить. И много раз разработчики просто отказываются от этого и говорят: "Хорошо, что угодно. Ну, это будет бесплатно, когда приложение отключится", и это не такой хороший план.

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

Полная транскрипция

Ответ 12

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

Ответ 14

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

Книга Джеффри Рихтера CLR через С# содержит хорошую главу о том, как управляется память в .NET.

Ответ 15

Лучший пример, который я нашел, был на самом деле с Java, но тот же принцип применяется к С#.

Мы читали текстовые файлы, которые состояли из множества длинных строк (каждая строка была несколько МБ в куче). Из каждого файла мы искали несколько подстрок ключей и содержали только подстроки. После обработки нескольких сотен текстовых файлов у нас закончилась нехватка памяти.

Оказалось, что string.substring(...) сохранит ссылку на исходную длинную строку... хотя мы сохранили только 1000 символов или около того, эти подстроки все равно будут использовать по несколько МБ памяти. По сути, мы сохранили содержимое каждого файла в памяти.

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

Изменить: не уверен, что эта специфическая проблема заражает .NET. Идея состояла в том, чтобы проиллюстрировать фактический дизайн/оптимизацию, выполненную на языке сбора мусора, который в большинстве случаев был интеллектуальным и полезным, но может привести к нежелательному использованию памяти.

Ответ 16

А если вы используете управляемую dll, но dll contians небезопасный код? Я знаю, что это разделение волос, но если у вас нет исходного кода, то с вашей точки зрения вы используете только управляемый код, но вы все равно можете течь.