Как избавиться от объекта в C # - PullRequest
6 голосов
/ 13 февраля 2009

В следующем коде c # как избавиться от объектов, когда они больше не нужны? Об этом позаботятся автоматически или мне нужно что-то сделать?

public void Test()
{
   object MyObject = new object();

   ... code ...
}

Ответы [ 7 ]

18 голосов
/ 13 февраля 2009

Автоматически. Когда MyObject выходит из области видимости (в конце теста), он помечается для сбора мусора. В какой-то момент в будущем среда выполнения .NET очистит память для вас

Edit: (Для полноты картины я должен указать, что если вы передадите MyObject куда-нибудь, он будет передан по ссылке и не будет собирать мусор - только когда больше нет ссылок на объект, GC свободен для его сбора. )

Редактировать: в сборке релиза MyObject обычно собирается, как только он не используется (см. Мой ответ для более подробной информации --dp)

5 голосов
/ 13 февраля 2009

Краткий ответ: если у вас нет неуправляемых ресурсов (файловых дескрипторов и т. Д.), Вам не о чем беспокоиться.

Длинный ответ немного сложнее.

Когда .NET решает освободить часть памяти, он запускает сборщик мусора . Это ищет все объекты, которые все еще используются, и помечает их как таковые. Любая локальная переменная (в любом стековом фрейме любого потока), которая все еще может быть прочитана, считается как root , как и статические переменные. (На самом деле я считаю, что на статические переменные ссылаются с помощью живых объектов Type, на которые ссылаются с помощью живых объектов AppDomain, но по большей части вы можете рассматривать статические переменные как корни.)

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

Это очень широкая концептуальная картина - но она становится намного более подробной, когда вы думаете о поколенческой модели сборки мусора, финализаторов, параллельной сборки и т. Д. Я настоятельно рекомендую вам прочитать * 1017 Джеффа Рихтера * CLR через C # , который подробно описан в этом. У него также есть статья two part (начиная с 2000 года, но все еще очень актуальная), если вы не хотите покупать книгу.

Конечно, все это не означает, что вам не нужно беспокоиться об использовании памяти и времени жизни объектов в .NET. В частности:

  • Создание объектов бессмысленно будет стоить производительности. В частности, сборщик мусора работает быстро, но не бесплатно. Ищите простых способов уменьшить использование памяти при кодировании, но микрооптимизация до того, как вы поймете, что у вас есть проблема, тоже плохо.
  • Возможно «утечка» памяти, делая объекты доступными дольше, чем вы предполагали. Две достаточно распространенные причины этого - статические переменные и подписки на события. (Подписка на событие делает обработчик событий доступным от издателя событий, но не наоборот.)
  • Если вы используете больше памяти (живым, доступным способом), чем у вас есть, ваше приложение вылетит. .NET не может многое сделать, чтобы предотвратить это!
  • Объекты, которые используют ресурсы вне памяти, обычно реализуют IDisposable. Вы должны вызвать Dispose для них, чтобы освободить эти ресурсы, когда вы закончите с объектом. Обратите внимание, что не не освобождает сам объект - это может сделать только сборщик мусора. Оператор using в C # является наиболее удобным способом надежного вызова Dispose даже при наличии исключения.
4 голосов
/ 13 февраля 2009

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

3 голосов
/ 13 февраля 2009

В оптимизированном коде возможно и вероятно, что MyObject будет собран до конца метода. По умолчанию конфигурация отладки в Visual Studio будет создаваться с включенным переключателем отладки и выключенным оптимизатором, что означает, что MyObject будет сохраняться до конца метода (чтобы вы могли посмотреть значение во время отладки). Сборка с отключенной оптимизацией (в данном случае отладка не имеет значения) позволяет собирать MyObject после того, как он определен как неиспользованный. Один из способов заставить его остаться в живых до конца метода - вызвать GC.KeepAlive (MyObject) в конце метода.

2 голосов
/ 13 февраля 2009

Это заставит сборщик мусора избавиться от неиспользуемых объектов.

GC.Collect();
GC.WaitForPendingFinalizers();

Если вы хотите, чтобы конкретный объект был собран.

object A = new Object();
...
A = null;
GC.collect();
GC.WaitForPendingFinalizers();
1 голос
/ 13 февраля 2009

Обычно сбор мусора может зависеть от очистки, но если ваш объект содержит какие-либо неуправляемые ресурсы (соединения с базой данных, открытые файлы и т. Д.), Вам необходимо явно закрыть эти ресурсы и / или исключить метод dispose для объекта (если реализует IDisposable). Это может привести к ошибкам, поэтому вы должны быть осторожны при работе с этими типами объектов. Простого закрытия файла после его использования не всегда достаточно, поскольку исключение перед выполнением закрытия оставит файл открытым. Либо используйте блок using, либо блок try-finally.

Итог: "использование" - твой друг.

1 голос
/ 13 февраля 2009

Об этом позаботятся автоматически.

...