2009-08-03 3 views
6

Я понимаю, что на управляемом языке, таком как Java или C#, это называется сборщиком мусора, который каждый раз проверяет, есть ли любые экземпляры объектов, которые больше не ссылаются и, таким образом, полностью потеряли силу и затем освобождаются от памяти. Но если два объекта не ссылаются на какую-либо переменную в программе, а ссылаются друг на друга (например, на подписку на события), сборщик мусора будет видеть эту ссылку и не очищать объекты от памяти.Почему сборщик мусора не выясняет, когда объекты, ссылающиеся друг на друга, действительно осиротевшие

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

+5

На самом деле, это одна из проблем со средами подсчета ссылок, которые ** позаботились о ** в .NET GC. –

+0

Еще одна традиционная функция Lisp, проникающая в среднюю среду. –

ответ

24

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

Подробный обзор сборщика мусора CLR можно найти в this MSDN article и в this blog post.

Примечание: На самом деле, GC, даже не «видит» эти типы объектов во время марки фазы, поскольку они недостижимы, и, следовательно, получить собранные во время подметать.

+0

Хорошо, что делает вещи намного проще. Таким образом, моя программа имеет древовидную структуру, состоящую из узлов, каждая из которых отображается через собственный TreeNode в виде дерева. Если ничто не ссылается на Node или TreeNode, тогда мне не нужно беспокоиться об отсоединении событий или ссылок между ними. –

7

Большинство GC не работают с подсчетом ссылок больше. Обычно они (и это происходит как на Java, так и на .NET) работают с возможностью доступа из корневого набора объектов. Корневой набор объектов - это глобальные и стековые ссылочные экземпляры. Все, что доступно из этого набора прямо или косвенно, является живым. Остальная часть памяти недоступна и, следовательно, подвержена сбору.

+0

На самом деле, я считаю, что неправильно ссылаться на Reference-Counting на форму Garbage-Collection. Это две отдельные формы управления памятью. –

+0

Подсчет ссылок (RC) - это форма сбора мусора (GC). Простой алгоритм RC не может иметь дело с циклическими ссылками, но есть техника Боброва, алгоритм слабого указателя и алгоритмы частичной маркировки, которые могут. – mtasic85

2

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

Прикрепите себя, например. на событие App.Idle в Windows Forms, и ваш объект будет сохранен в живых для оставшегося срока службы приложения. Зачем? Это статическое приложение будет содержать ссылку (хотя бы косвенно через делегата) зарегистрированного наблюдателя. Несмотря на то, что вы, возможно, выбрали своего наблюдателя, он все еще привязан к App.Idle. Вы можете построить многие из этих примеров.

1

Другие ответы здесь, конечно, правильные; .NET делает это сборку мусора, основанную на достижимости объекта.

Что я хотел добавить: Я могу порекомендовать прочитать Understanding Garbage Collection in .NET (статья простого английского Эндрю Хантера), если вы хотите получить более подробную информацию.

2

Это главный недостаток традиционных reference counting garbage collection. Свойство сборщика мусора, описывающее это поведение, является неполным сборщиком. Другие коллекторы в значительной степени попадают в категорию под названием трассировочные сборщики мусора, которые включают в себя традиционные маркировочные, полупространственные/уплотняющие и гибридные генераторы и не страдают от этих недостатков (но сталкиваются с несколькими другими).

Все реализации JVM и CLI Я знаю об использовании полных коллекционеров, что означает, что они не страдают от конкретной проблемы, о которой вы просите здесь. Насколько мне известно, из них Jikes RVM является единственным, поставляющим опорный счетный коллектор (один из его многочисленных).

Еще одна интересная вещь, которую следует отметить, - это решение проблемы полноты в подсчете сбора мусора, а resulting collectors демонстрируют некоторые интересные характеристики производительности, которые трудно вывести из трассировочных коллекционеров. К сожалению, самые эффективные алгоритмы сбора мусора для подсчета ссылок и наиболее полнота модификаций зависят от помощи компилятора, поэтому приведение их в C++ shared_ptr<T> сложно/не происходит. Вместо этого у нас есть weak_ptr<T> и documented rules (извините за субоптимальную ссылку - видимо, документация ускользает от меня), просто избегая проблем. Это isn't the first time (другая посредственная ссылка), мы видели такой подход, и надеемся, что дополнительная работа по предотвращению проблем с памятью будет меньше объема работы, необходимой для поддержания кода, который не используется shared_ptr<T> и т. Д.

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

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