2012-01-12 5 views
47

Рассмотрим эти два класса:мусора коллектора и циклическая ссылка

public class A 
{ 
    B b; 
    public A(B b) { this.b = b; } 
} 

public class B 
{ 
    A a; 
    public B() { this.a = new A(this); } 
} 

Если я классы предназначены, как и выше, будут объектами таких классов будут собраны сборщика мусора (GC)?

Предположим, я делаю это:

void f() 
{ 
    B b = new B(); 
} 

В этом методе я создаю экземпляр B под названием b, а когда возвращается метод, b выходит из области видимости, и GC должен быть в состоянии собрать его , но если бы он собирал его, ему было бы необходимо сначала собрать a, который является членом B, и для сбора a ему необходимо сначала собрать b, который является членом A. Он становится круговым. Поэтому мой вопрос: является ли такая циркулярная ссылка предотвращением сбора объектов GC?

  • Если да, то как мы можем избежать этой проблемы? Как мы можем убедиться, что у нас нет круговой ссылки в нашем классе? Есть ли какой-либо инструмент (или параметр компилятора), который помогает нам обнаруживать циклическую ссылку?
  • Если нет, то где и почему мы используем класс WeakReference? В чем его цель?
+1

Посмотрите здесь http://stackoverflow.com/questions/400706/circular-references-cause-memory-leak –

+0

По крайней мере, логически одна из ссылок всегда будет слабой: в вашем примере, cleary 'A 'не может зависеть от' B', потому что 'A' должен быть сделан первым, как член' B', и поэтому 'A' может содержать только слабую ссылку на' B'. Таким образом, безопасно уничтожать «B» сначала, а затем «A». Рассуждая рекурсивно, каждая компьютерная программа должна быть таким образом. Никогда не может быть * истинной *, полностью симметричной круговой зависимости. –

+0

@ KerrekSB: Я согласен с этой логикой. Но это рассматривается с точки зрения творения. Будет ли GC анализировать это (т. Е. Код в каждом методе таких классов, ведь только тогда он может достичь этого вывода)? Я имею в виду, если вы видите объекты после их создания, то это выглядит очень проблематично. – Nawaz

ответ

74

Сборщик мусора .Net может абсолютно обращаться с круглыми ссылками. Вид высокого уровня очень, как работает сборщик мусор ...

  • Начните с местными жителями, статикой и ГЦ возлагали объекты. Ни один из них не может быть собран
  • Отметьте каждый объект, который может быть достигнут путем перемещения детей этих объектов.
  • Соберите каждый объект, который не отмечен.

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

Примечание: Я понимаю, что я оставил из много забавных деталей, чтобы сохранить этот ответ простой и прямой

+0

Не будет ли это дорогостоящим –

25

Нет, это не будет проблемой, потому что GC может обрабатывать циклические ссылки

MSDN говорит

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

+1

И это то, что делает этот язык отличным! – Aggressor

5

Нет, что циклическая ссылка не будет влиять на сборщик мусора, и это будет вполне в состоянии собрать экземпляр В.

Сборщик мусора знает, что никто не может ссылаться на экземпляр B после перехода и, следовательно, никто не может использовать экземпляр B для косвенной ссылки A.

5

Несколько ответов уже объяснил, что циклические ссылки не являются проблемой.

Что касается слабых ссылок - причина их использования - кеширование.

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