Существуют ли ситуации, когда использование не избавится от объекта? - PullRequest
3 голосов
/ 23 февраля 2012

Существуют ли ситуации, когда использование не приведет к удалению объекта, от которого он должен избавиться?

Например,

using(dbContext db = new dbContext()){ ... }

есть ли способ, чтобы после последнего } дБ все еще было?

Что если возникнет такая ситуация:

object o =  new object();
using(dbContext db = new dbContext()){
 o = db.objects.find(1);
}

Возможно ли, что o сможет сохранить db в живых?

Ответы [ 10 ]

6 голосов
/ 23 февраля 2012

Я думаю, что вы путаете два понятия: утилизация и сбор мусора.

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

Так, в вашем примере, db.Dispose будет вызываться в конце блока using (который закроет соединение), но на DbContext все равно будет ссылаться o. Поскольку o является локальной переменной, DbContext будет иметь право на сборку мусора, когда метод вернется.

5 голосов
/ 23 февраля 2012

Живой и Уничтоженный - это две совершенно разные вещи.

Если o - это объект, который содержит ссылку (через поле, свойство, сам и т. Д.) На объект dbContext, и сборщик мусора определяет, что оба oи объект dbContext все еще доступен, тогда этот объект будет поддерживаться.Тем не менее, объект все равно будет удален, как только выполнение выйдет из блока using нормально.

4 голосов
/ 23 февраля 2012

db будет присутствовать до тех пор, пока не выйдет из области видимости, все ссылки на него не будут потеряны, и GC решит подключиться. Вызов Dispose не очищает сам объект , он сообщает объект для очистки любых собственных ресурсов, на которых он держится.

Интерфейс IDisposable предназначен для управления собственными ресурсами, которыми GC не может управлять. Сам объект является управляемым объектом, о котором заботится GC. В вашем примере этот объект, вероятно, поддерживает соединение с базой данных, которая является собственным ресурсом.

GC не может очистить это, поэтому для детерминированного управления этой памятью / ресурсом класс реализует IDisposable, чтобы сказать клиентам: «эй, вам нужно проделать дополнительную работу, чтобы убедиться, что ресурсы, которые мне нужны, о моей работе заботятся настолько эффективно, насколько это возможно. "

Кстати, правильная реализация IDisposable высвободит все собственные ресурсы в финализаторе, поэтому вы не должны испытывать утечку памяти, если не вызовете Dispose. Тем не менее, это не является детерминированным, и вы можете очень хорошо испытывать проблемы при этом. Хорошая практика требует, чтобы вы освободили эти ресурсы как можно скорее, поэтому вы сами звоните Dispose.

2 голосов
/ 23 февраля 2012

Возможно ли, что o может поддержать БД?

Жив в том смысле, что его не собирают: Да.

Но блок using() {} подразумевает Dispose(), а это означает Close(), поэтому вы больше не сможете использовать его для чего-либо значимого.

2 голосов
/ 23 февраля 2012

Объект может быть жив с точки зрения ГХ после окончания использования блока, но он будет удален. Во втором примере, если бы db.objects.find(1) вернул ссылку на db (что было бы странно), вы бы получили что-то вроде этого:

object o;
using (dbContext db = new dbContext())
{
    o = db;
}

// at this point in the code, the object is disposed,
// but referenced by the variable o; the object is
// therefore not yet eligible for garbage collection.
1 голос
/ 23 февраля 2012

Чтобы добавить еще одну точку зрения ко всем ответам («утилизирован» или «собранный мусор»).

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

Поскольку «использование» не делает никаких волшебных вещейэто будет следовать за контрактом объекта на части «закрыть ресурсы», но это не обязательно означает «специальный ресурс теперь свободен».Поэтому после использования объект определенно «утилизируется», может быть «живым» с точки зрения GC, и фактический ресурс, которым управляет объект, может или не может быть освобожден (т. Е. Выгружен из памяти / закрыты собственные дескрипторы).

1 голос
/ 23 февраля 2012

Нет, db всегда будет утилизироваться.

Не смешивайте концепцию утилизации объекта и объекта, собираемого ГХ.Утилизация - это инструмент для освобождения ресурсов, используемых объектом, но вы всегда можете сохранить живую ссылку на удаленный объект, который предотвратит сбор объекта.Один не исключает другой.

Шаблон Dispose - это просто способ детерминированного освобождения ресурсов, даже если объект не собран GC (что будет сделано, когда нет живых ссылок и , когда ГХ решает собрать объект, который нельзя знать заранее, если вы явно не вызовете GC.Collect).

1 голос
/ 23 февраля 2012

конструкция using эквивалентна блоку try-finally:

dbContext db = new dbContext();
try
{
   o = db.objects.find(1);
}
finally
{
   db.Dispose();
}

В большинстве случаев нормального выполнения программы вызывается db.Dispose ().Тем не менее, это не означает, что БД по-прежнему не будет действительным объектом в памяти.Как сказал Эд в своем ответе, Dispose () фактически не удаляет объект из кучи и не освобождает память.Это происходит только тогда, когда объект, на который в данный момент ссылается переменная db, теряет все ссылки (потому что они вышли из области видимости или переназначены), а GC удаляет его.

Однако удаленный объект, как правило, не очень полезен дляхранить в памяти;Dispose () обычно является концом дороги, прежде чем объект выходит из области видимости и имеет GCed.Поэтому, несмотря на то, что вы МОЖЕТЕ хранить базу данных, создавая или присваивая ссылку на нее другой переменной, вы, скорее всего, вызовете ошибки из-за того, что объект закрыл свои соединения, освободил неуправляемые ресурсы, такие как COM-ссылки или сокеты, и в целом подготовил себя к удалениюиз памяти с вызовом Dispose ().

1 голос
/ 23 февраля 2012

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

Если вы на самом деле установите o = db, это будет другая история, но вы имеете дело с наборами результатов.

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

Кстати, оператор использования по сути такой же (скомпилируйте оба и проверьте с отражателем, если сомневаетесь):

try
{
   var myObject = new MyObject();
}
finally
{
   myObject.Dispose();
}
1 голос
/ 23 февраля 2012

using гарантирует, что IDisposable.Dispose будет вызываться для целевого объекта, когда выполнение выходит из блока using.Это будет происходить всегда, несмотря ни на что.

Непонятно, что вы имеете в виду, что o может сохранить db живой - db будет уничтожен, поэтому вы, вероятно, получите ObjectDisposedException, если выпопробуйте использовать его потом.Это считается "мертвым"?Если да, то он мертв, Джим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...