Когда избавляться и почему? - PullRequest
10 голосов
/ 21 октября 2010

Я задал вопрос об этом методе:

// Save an object out to the disk
public static void SerializeObject<T>(this T toSerialize, String filename)
{
    XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
    TextWriter textWriter = new StreamWriter(filename);

    xmlSerializer.Serialize(textWriter, toSerialize);
    textWriter.Close();
}

в ответ я получил это как дополнительное замечание:

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

Итак, я могу сказать, что это покажется супер хромым для человека, который кодирует C # в течение года или двух, нопочему я должен его утилизировать?

Видит ли, что testWriter имеет метод dispose, но разве сборщик мусора не должен об этом заботиться?Я пришел из Delphi в C #.В Delphi мне пришлось все вычистить, поэтому я не хочу быть ленивым.Мне просто сказали, что если вы заставите освободить память, которую занимают ваши объекты, это может привести к плохим вещам.Мне сказали: «Просто позвольте сборщику мусора сделать это».

  1. Итак, зачем мне вызывать dispose?(Я предполагаю, что это потому, что textWriter попадает на диск.)
  2. Есть ли список объектов, с которыми мне нужно быть осторожнее?(Или простой способ узнать, когда мне нужно позвонить утилизировать?)

Ответы [ 12 ]

15 голосов
/ 21 октября 2010

Практическое правило здесь довольно простое: всегда вызывайте Dispose() для объектов, которые реализуют IDisposable (не все объекты делают).Вы не всегда будете знать причину, по которой объект должен был реализовывать Dispose, но вы должны предположить, что он существует по какой-то причине.

Самый простой способ убедиться в этом - через using:

using (TextWriter tw = new StreamWriter(fileName))
{
   // your code here
}

Это вызовет Dispose() автоматически в конце блока использования (это в основном то же самое, что использование try / catch / finally с Dispose () в блоке finally).

Для получения дополнительной информации о том, как Dispose работает со сборкой мусора, см. Здесь .

12 голосов
/ 21 октября 2010

Вы правы, что для правильно написанного кода GC в конечном итоге очистит собственные ресурсы. У объекта будет финализатор, и во время финализации освободятся необходимые нативные ресурсы.

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

  • Файлы открываются долгое время после того, как они больше не используются
  • Дескрипторы ресурса могут закончиться, потому что GC не видит достаточного давления памяти для принудительного сбора и, следовательно, запускает финализаторы

Шаблон using / dispose добавляет детерминизм к очистке собственных ресурсов и устраняет эти проблемы.

4 голосов
/ 21 октября 2010

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

4 голосов
/ 21 октября 2010

Если вы знаете, что не собираетесь использовать определенный ресурс, вы можете просто распорядиться им самостоятельно; вы наверняка будете быстрее сборщика мусора и позволите другим использовать файл или что-то еще, что вы открыли быстрее. Самый простой способ - это использовать ваш TextWriter или любой другой ресурс в using:

using (TextWriter textWriter = new StreamWriter(filename))
{
    xmlSerializer.Serialize(textWriter, toSerialize);
}

Это в основном гарантирует, что TextWriter будет расположен в конце. Во всяком случае, вам это не нужно.

3 голосов
/ 21 октября 2010

Ну, на самом деле вы уже утилизируете его, так как метод textWriter.Close делает это.

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

Таким образом, вы можете изменить свой код на.Это

public static void SerializeObject<T>(this T toSerialize, String filename)
{
    TextWriter textWriter;
    try
    {
         XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
         textWriter = new StreamWriter(filename);

          xmlSerializer.Serialize(textWriter, toSerialize);
    }
    finally
   {
       textWriter.Close();
   }

Что очень похоже на то, что делает using () в других ответах.

Результатом отсутствия этого является то, что если в Serialize произойдет ошибка, пройдет некоторое время, прежде чем Framework откажется от блокировки файла (когда она обрабатывает очередь fReachable).

Я знаюFxCop сообщает вам, когда следует внедрить IDisposable, но я не думаю, что есть какой-либо простой способ выяснить, когда вам нужно вызвать Dispose, кроме просмотра документов и определения, влияет ли объект на IDisposable (или intellisense).

2 голосов
/ 21 октября 2010

Если вы используете собственные ресурсы (например, файловые дескрипторы), то вы должны вызывать Dispose (), чтобы закрыть их в ближайшее время, а не во время работы GC (что может быть намного позже в старших поколениях gc).И вы хотите закрыть файл, так как доступ к файлу обычно каким-то образом блокирует файл.

1 голос
/ 21 октября 2010

Из TextWriter.Dispose документации:

Примечание Всегда звоните утилизировать перед вами отпустите последнюю ссылку на TextWriter. В противном случае ресурсы он не будет освобожден до сборщик мусора вызывает Метод Finalize объекта TextWriter.

Из Object.Finalize документации:

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

и

Метод Finalize может не работать завершение или не может работать вообще в следующие исключительные обстоятельства:

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

  • Процесс завершается без предоставления во время выполнения шанс убраться. В в этом случае среда выполнения первая уведомление о завершении процесса уведомление DLL_PROCESS_DETACH.

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

1 голос
/ 21 октября 2010

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

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

0 голосов
/ 21 октября 2010

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

0 голосов
/ 21 октября 2010

Обычно вы должны утилизировать объекты, когда они вам больше не нужны.

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

...