Объект не удаляется после вызова функции Dispose () - PullRequest
0 голосов
/ 07 мая 2010

У меня есть вопрос относительно утилизации объекта.Сценарий выглядит следующим образом.

В настольном приложении, разработанном на C #, у меня есть функция, в которой объект создается следующим образом.

namespace Class 1
{
    variables section;
    ....
    ....

    Function1()
    {
         local variables;
         try
         {
              Object1 obj = new Object1();
              ....
              ....
              if(true)
              {
                  ....
              }
              else
              {
                   **obj.Dispose();**
              }
          }
          catch()
          {}
          finally
          {}
     }
}

Объект не располагается, когдаостальная часть выполнена.Ссылка msdn для этого:

http://msdn.microsoft.com/en-us/library/system.componentmodel.component.dispose(VS.90).aspx

, согласно которой компонент должен реализовывать все используемые им ресурсы.

Я хотел бы знать, почему объектне утилизируется.

Спасибо.

Паван Навали.

Ответы [ 6 ]

4 голосов
/ 07 мая 2010

Поскольку создается впечатление, что ваш пользовательский объект наследуется от System.ComponentModel.Component, вам потребуется переопределить Dispose(bool), чтобы распорядиться ресурсами вашего объекта. Хотя ваш объект наследует от System.ComponentModel.Component (который имеет метод Dispose), пользовательские ресурсы вашего объекта не будут утилизироваться, если вы не создадите для этого метод dispose. (Это не автоматическая вещь, которую вы получаете, наследуя от System.ComponentModel.Component. Будут выбрасываться только ресурсы, известные базовому классу System.ComponentModel.Component.)

Попробуйте что-то подобное в своем классе:

protected override void Dispose(bool disposing)
{
    // release your resources here
}

Мы не знаем, какие ресурсы на вашем объекте не утилизируются, но каким бы ни был объект, метод dispose должен быть закодирован так, чтобы он высвобождал ресурсы. Если ресурс объекта не удаляется в методе dispose, он не удаляется при его удалении.

Например:

ExpensiveResource myExpensiveResource1;
ExpensiveResource myExpensiveResource2;

void Dispose()
{
    // release the resources
    myExpensiveResource1.Dispose();

    // since there is no call to dispose of myExpensiveResource2, it is not disposed of
}
3 голосов
/ 07 мая 2010

IDisposable.Dispose - это просто метод, который класс может выбрать для реализации. Содержимое этого метода полностью определяется разработчиком класса. Чтобы точно понять, что происходит, есть ряд терминов, которые вы должны понимать, когда речь идет об утилизации / завершении объекта.

Располагая

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

Доработка

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

Как узнать, что утилита Dispose запущена?

Что ж, лучший способ - установить точку останова в методе Dispose. Если у вас нет исходного кода, вы можете использовать этот метод .

Могу ли я сказать, что утилита Dispose запущена, увидев, что память, используемая процессом, отключается?

Нет. После запуска Dispose объект CLR все еще существует. Память освобождается в пул управляемой памяти после завершения объекта. Если вы точно знаете, что это за ресурс, вы можете использовать сторонние инструменты ОС, такие как Process Explorer , например, чтобы увидеть, выпустил ли процесс дескриптор файла. Даже в этом случае между процессом освобождения дескриптора и операционной системой может возникнуть задержка, которая думает, что она освобождена.

Как узнать, что объект был завершен?

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

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

Если вы попытаетесь выяснить, что делает ваше приложение, посмотрев на объем памяти, который оно потребляет в Process Manager, я могу гарантировать, что вы сойдете с ума, пытаясь проанализировать. Фактически, попытка сделать это наравне с попыткой использовать регулярные выражения для анализа HTML .

Заключение

Ничего из этого на самом деле не отвечает на ваш вопрос. Итак, вот контрольный список, чтобы выяснить вашу проблему, так как нам нечем заняться:

  1. Откуда вы знаете, что Dispose не запускается? Вы отладили приложение и установили точку останова в этой строке: **obj.Dispose();**?
  2. Если точка останова сработала, вы прошли через код, чтобы выяснить, что происходит?
  3. Можете ли вы уточнить, что вы подразумеваете под Объект не утилизирован ?
2 голосов
/ 07 июня 2010

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

Эти понятия легко спутать по двум причинам:

Во-первых, обычно рекомендуется работать с IDisposable объектами с помощью оператора using следующим образом:

using (IDisposable d = new MyDisposableObject ()) {
    // do whatever you need d for
}

, который обеспечивает удаление d при выходе из блока using; но он также ограничивает область действия d блоком, а это означает, что, как только исполняется блок, объект также может свободно собирать мусор (не обязательно, что это будет немедленно, но это ни здесь, ни их, поскольку ваш код дольше сохраняет ссылку на него). Таким образом, в этой (чрезвычайно распространенной и, вероятно, следует считать стандартной) идиоме, удаление происходит одновременно с удалением ссылок.

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

В случае, когда вы явно вызываете Dispose () для метода, например, в своем вопросе (при условии, конечно, что Object1 реализует IDisposable), вы все равно сохраняете ссылку на obj, и, как следствие, из этого могут получить доступ ко всем его свойствам и методам. Конечно, совершенно разумно, чтобы эти методы или свойства требовали неуправляемого ресурса, который вы уже утилизировали, и в этом случае может быть выброшен System.ObjectDisposedException, или же авторы Object1 решили использовать этот случай, но для них также вполне разумно функционировать, как ожидается, если им не требуются ресурсы, которые вы освободили.

В качестве примера посмотрите на System.IO.FileStream. Как только вы избавитесь от него, такие операции, как ReadByte (), выдают исключение, поскольку очевидно, что нет доступа к файлу для чтения, но вызов свойства CanRead просто возвращает false, что является допустимым и ожидаемым. (Например, MemoryStream может даже получить доступ к данным после вызова Dispose (), поскольку (текущая) реализация использует буфер, управляемый средой выполнения, а не что-то вроде дескриптора ядра).

2 голосов
/ 07 мая 2010

Не видя ваш код, трудно сказать наверняка, но вы можете ошибочно принять «Dispose» с другой концепцией, такой как деструктор в c ++ или delete / free

0 голосов
/ 07 мая 2010

Вы должны рефакторинг вашего кода, чтобы он выглядел так:

Function1()
{
  local variables;
  try
  {
     using (Object1 obj = new Object1())
     {
       ....
       ....
       if(true)
       {
         ....
       }
     }
  }
  catch() // I hope you don't use try-catch like this in real code
  {}      // I hope you don't use try-catch like this in real code
  finally // I hope you don't use try-catch like this in real code
  {}      // I hope you don't use try-catch like this in real code
}

Оператор using гарантирует, что Dispose для объекта obj всегда вызывается, когда он покидает область действия.

0 голосов
/ 07 мая 2010

«Другая часть» выполняется в первую очередь? Вы говорите, что «если часть» всегда верно

...