2010-10-21 2 views
10

Я спросил 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.

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

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

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

http://www.stackoverflow.com/questions/1691846/does-garbage-collector-call-dispose –

+0

Насколько я понимаю, это приводит к тому, что GC знайте, что это готово к сбору, вместо того, чтобы проверить, готов ли он.Кроме того, вы можете сказать GC собирать «ранний» на этом элементе, вместо того, чтобы рамка висела на нем какое-то время «на всякий случай» http://www.devx.com/dotnet/Article/33167 – jcolebrand

+4

@drachenstern - популярное заблуждение, но неверное. Dispose просто предоставляет вам механизм принудительного закрытия неуправляемых ресурсов, таких как дескрипторы файлов или сетевые сокеты, как только вы закончите с ними, не дожидаясь сбора мусора. Он не сигнализирует GC о сборе объекта. – Paolo

ответ

12

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

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

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

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

1

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

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

2

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

4

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

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

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

+3

, вероятно, не нужно делать как Close, так и Dispose –

+0

@ Кондрайда, я знаю. Я оставил его код в основном так, как он был, просто чтобы показать ему, что ему мало что нужно изменить. – alex

4

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

+0

«Сборщик мусора выпускает все ресурсы» Не обязательно: Представьте, что Боб подписался на событие более долгоживущего объекта (например, это AppDomain). GC никогда не очистит Боба, если вы не скажете ему отказаться от этого мероприятия! – Niki

+0

Правильно, GC просто вызывает финализатор, ответственность разработчика за выпуск ресурсов в Dispose/finalizer лежит на классе. Я говорил об использовании одноразовых .NET-классов, таких как TextWriter, из вопроса, которые (надеюсь) написаны правильно. –

15

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

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

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

Это будет вызывать Dispose() автоматически в конце с помощью блока (это принципиально так же, как с помощью TRY/поймать /, наконец, Dispose() в блоке finally).

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

0

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

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

0

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

1

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

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

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

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

и

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

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

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

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

0

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

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

3

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

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

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

0

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

+0

Не очень полезный ответ ... –

+0

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

Смежные вопросы