Как сборка мусора работает на объектных ссылках? - PullRequest
9 голосов
/ 13 августа 2010

Я запутался в процессе сбора мусора на объектах.

object A = new object();
object B = A;        
B.Dispose();

Вызывая Dispose только для переменной B, созданный объект не будет собирать мусор так как на объект все еще ссылается А.

Теперь следующий код работает так же, как и выше?

public static image Test1()
{
    Bitmap A = new Bitmap();
    return A;
}

Теперь я вызываю эту статическую функцию из другого метода.

public void TestB()
{
   Bitmap B = Test1();
   B.Dispose();
} 

Статическая функция Test1 вернула ссылку на объект Bitmap. Ссылка сохранена в другой переменной B. При вызове Dispose для B связь между B и объектом теряется, но что происходит со ссылкой, переданной из Test1. Будет ли он активен, пока не закончится область действия функции TestB

Есть ли какой-нибудь способ избавиться от ссылки, которая сразу передается из статической функции?

Ответы [ 7 ]

16 голосов
/ 13 августа 2010

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

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

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

15 голосов
/ 13 августа 2010

Я могу быть выключен, но вы, кажется, неправильно понимаете Dispose и сборку мусора.Объект будет удален после того, как все ссылки на него будут удалены недетерминированным способом.Утилизация обычно избавляет от неуправляемых ресурсов, поэтому объект готов к сборке мусора.В первом примере вы удалили объект, теоретически сделав его непригодным для использования, но он все еще существует в куче, и у вас все еще есть ссылка на него, как A, так и B. Как только они выйдут из области видимости, сборщик мусора может восстановить эту память, но не всегда.В примере 2 битовая карта A помещается в кучу, затем вы возвращаете ссылку на нее и устанавливаете B на эту ссылку.Затем вы утилизируете его, и Б выходит из области видимости.На этом этапе больше нет ссылок на него, и он будет собирать мусор на более позднем этапе.

5 голосов
/ 13 августа 2010

Бывает, что Раймонд Чен только что написал серию постов в блоге, описывающих аспекты сборки мусора .NET. Этот пост имеет самое непосредственное отношение к вашему вопросу (когда объекты собираются в мусор?).

3 голосов
/ 13 августа 2010

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

2 голосов
/ 13 августа 2010

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

Одна из причин заключается в том, что управляемый объект может иметь неуправляемый ресурс, который занимает несколько гигабайт оперативной памяти, но для GC он выглядит как 8 байтов или около того.

С файлами, conb db и т. Д. Вы часто хотите закрыть их как можно скорее, чтобы освободить неуправляемые ресурсы и избежать проблем с блокировкой.

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

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

Использование оператора () является благословением.

PS. Довольно часто я реализую IDisposable, даже если у меня нет прямых неуправляемых ресурсов, однако его importnt, чтобы сообщить всем переменным-членам, которые реализуют IDisposable и Dispose, был вызван.

1 голос
/ 13 августа 2010

Хорошо для начала Утилизировать! = Сбор мусора.Вы можете вызвать dispose и никогда не собирать мусор, потому что «Disposed Object» может иметь ссылки на него.Метод dispose используется для «приведения в порядок» объекта перед запуском CG (закрытие открытых подключений БД, файловых подключений и т. Д.).

object A = new object();
object B = A;        
B.Dispose();

В этом случае B.Dispose вызывает метод dispose дляA, потому что B ссылается на объект в переменной A. Ни один из них не будет CGd, потому что они еще не выпали из области видимости.

public static image Test1()
{
    Bitmap A = new Bitmap();
    return A;
}

Здесь происходит то, что вы создаете объект A и возвращаететак что, когда вы выходите из Test1, A, скорее всего, ссылается на другую переменную в вызывающем методе.Это означает, что даже если вы покинули метод, A по-прежнему укоренен (скорее всего) и не будет CG'd до тех пор, пока с ним не завершится вызывающий метод.

public void TestB()
{
   Bitmap B = Test1();
   B.Dispose();
} 

Здесь создается Bи призывая распоряжаться.Это не значит, что он будет собою подделан.Как только программа покидает метод, B выпадает из области видимости, что означает, что он может быть собран при следующем вызове GC.

Когда использовать Dispose

0 голосов
/ 13 августа 2010

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

Основной вопрос в сборке мусора: «Может ли этот объект быть достигнут??»Пока в стеке находится объект, который имеет ссылку на ваш объект (или есть ссылка на этот объект где-то в иерархии объектов), этот объект не будет собирать мусор.

Пример:

ObjA создает ObjB, который создает ObjC.Obj C не будет собирать мусор, пока на него больше не ссылается ObjB, или пока ObjB больше не ссылается на ObjA, или пока нет объектов, которые сохраняют ссылку на ObjA.

Опять вопросСпросите: «Может ли на данный объект ссылаться что-либо в коде?»

...