C # слабая ссылка все еще действительна после объекта GC? - PullRequest
0 голосов
/ 10 июня 2019

У меня есть быстрый фрагмент кода для тестирования слабой ссылки, я ожидаю, что после того, как объект является GC, слабая ссылка больше не должна возвращать объектную ссылку. Но мой тест показывает, что этого не ожидается:

class Person
{
    private int mI = 3;
    public int MI { get => mI; set => mI = value; }
}
class UseWeakReference
{
    public static void Main(String[] args)
    {
        Person person = new Person();
        WeakReference<Person> wr = new WeakReference<Person>(person);

        wr.TryGetTarget(out Person p1);
        Console.WriteLine(p1);

        person = null;
        wr.TryGetTarget(out Person p2);
        Console.WriteLine(p2);

        p2 = null;
        System.GC.Collect();
        Thread.Sleep(1000);
        wr.TryGetTarget(out Person p3);
        Console.WriteLine(p3); // I expected null here becaure person is collected.
    }
}

Он печатает:

MyApp1.Person
MyApp1.Person
MyApp1.Person // Why still valid?

Где я ошибся?

Спасибо.

1 Ответ

1 голос
/ 10 июня 2019

Когда вы вызываете TryGetTarget по слабой ссылке, предполагая, что указанный объект еще не был собран, вы получаете сильную ссылку на этот объект.Вы делаете это 3 раза в своем коде: p1, p2 и p3 являются сильными ссылками на объект.Когда сборщик мусора запускается - автоматически или в вашем случае, когда вы принудительно собираете мусор - эти сильные ссылки не позволят собрать объект.

Вот версия, которая работает:

void Main()
{
    var person = new Person();
    WeakReference<Person> weak = new WeakReference<Person>(person);
    person = null;

    for (int i = 0; i < 10; i++)
    {
        Console.WriteLine($"{i}\t{TestReference(weak)}");
        Thread.Sleep(100);
    }

    GC.Collect();
    Console.WriteLine(TestReference(weak));
}

class Person
{
    private int mI = 3;
    public int MI { get => mI; set => mI = value; }
}

bool TestReference(WeakReference<Person> weak)
{
    if (weak.TryGetTarget(out Person p))
    {
        p = null;
        return true;
    }
    return false;
}

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

Даже вхотя этот код, если я закомментирую строку p = null;, сборщик мусора может не собрать объект. Попробуйте и посмотрите.

Мораль этой истории такова: когда вы получаете сильныйссылка из WeakReference<>, всегда обнуляет сильную ссылку, когда вы закончите с ней.

...