Когда распоряжаться и почему?

Я спросил question об этом методе:

// 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.

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

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

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

Ответ 1

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

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

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

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

Ответ 2

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

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

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

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

Подробнее о том, как Dispose работает с сборкой мусора, см. здесь.

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

Ну, на самом деле вы уже избавляетесь от него, поскольку метод 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();
   }

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

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

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

Ответ 6

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

Ответ 7

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

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

Ответ 8

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

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

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

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

и

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

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

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

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

Ответ 9

Сборщик мусора действительно "позаботится об этом". Рано или поздно. Когда дело доходит до вызова финализатора, после следующей сборки мусора.

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

Ответ 10

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

Ответ 11

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

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

Ответ 12

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