.Net Почему GC не удаляет объекты из кучи?

2

Я написал простую тестовую программу:

namespace GCTest {
class Program {
    static void Main(string[] args) {
        var a1 = new A();
        a1.AProperty = new A();
        a1.AProperty.AProperty = new A();
        a1.AProperty.AProperty.AProperty = new A();
        a1.AProperty.AProperty.AProperty.AProperty = new A();
        Console.WriteLine("a1 created");
        Console.ReadKey();

        var a2 = new A();
        a2.AProperty = new A();
        a2.AProperty.AProperty = new A();
        a2.AProperty.AProperty.AProperty = new A();
        a2.AProperty.AProperty.AProperty.AProperty = new A();
        Console.WriteLine("a2 created");
        Console.ReadKey();

        var a3 = new A();
        a3.AProperty = new A();
        a3.AProperty.AProperty = new A();
        a3.AProperty.AProperty.AProperty = new A();
        a3.AProperty.AProperty.AProperty.AProperty = new A();
        Console.WriteLine("a3 created");
        Console.ReadKey();

        var a4 = new A();
        a4.AProperty = new A();
        a4.AProperty.AProperty = new A();
        a4.AProperty.AProperty.AProperty = new A();
        a4.AProperty.AProperty.AProperty.AProperty = new A();
        Console.WriteLine("a4 created");
        Console.ReadKey();

        var a5 = new A();
        a5.AProperty = new A();
        a5.AProperty.AProperty = new A();
        a5.AProperty.AProperty.AProperty = new A();
        a5.AProperty.AProperty.AProperty.AProperty = new A();

        Console.WriteLine("a5 created");
        int a1Gen = GC.GetGeneration(a1);
        Console.WriteLine("a1 generation: " + a1Gen);
        GC.Collect();
        GC.WaitForPendingFinalizers();
        a1Gen = GC.GetGeneration(a1);
        Console.WriteLine("a1 generation: " + a1Gen);
        GC.Collect();
        GC.WaitForPendingFinalizers();
        a1Gen = GC.GetGeneration(a1);
        Console.WriteLine("a1 generation: " + a1Gen);
        GC.Collect();
        GC.WaitForPendingFinalizers();
        a1Gen = GC.GetGeneration(a1);
        Console.WriteLine("a1 generation: " + a1Gen);
        Console.ReadKey();

        a1 = a2 = a3 = a4 = a5 = null;
        Console.WriteLine("a1-a5 are null");
        Console.ReadKey();

        Console.WriteLine("GC");
        GC.Collect(2, GCCollectionMode.Forced);
        GC.WaitForPendingFinalizers();
        Console.ReadKey();

        Console.WriteLine("GC");
        GC.Collect(2, GCCollectionMode.Forced);
        GC.WaitForPendingFinalizers();
        Console.ReadKey();

        Console.WriteLine("GC");
        GC.Collect(2, GCCollectionMode.Forced);
        GC.WaitForPendingFinalizers();
        Console.ReadKey();

        Console.WriteLine("GC");
        GC.Collect(2, GCCollectionMode.Forced);
        GC.WaitForPendingFinalizers();
        Console.ReadKey();
    }
}

class A {
    int[] arr = new int[1000];
    public A() {
        arr[0] = 1;
    }

    public A AProperty { get; set; }
}

}

Я делаю снимки, используя встроенные средства диагностики Visual Studio 2017. Когда переменные a1 - a5 инициализируются, в куче есть 25 экземпляров A, как и ожидалось:

Изображение 174551

Но после того, как переменные a1-a5 станут равны нулю, даже после дополнительных вызовов метода GC.Collect, куча все еще содержит экземпляры A. И больше вызовов GC.Collect не уменьшают объекты A в куче. Зачем? Есть ли способ принудительно собрать ВСЕ неиспользованные предметы?

Изображение 174551

РЕДАКТИРОВАТЬ: я переключился на конфигурацию выпуска и я вижу, что в куче есть 15 объектов после инициализации переменных a1-a5:

Изображение 174551

А после вызовов GC.Collect по-прежнему остается 14 объектов.

  • 1
    Отладка или релиз сборки?
  • 0
    Отладка .Net 4.5
Показать ещё 4 комментария
Теги:
garbage-collection

1 ответ

4

Я не знаю, как VS справляется с этим, но если я запускаю ваш код, используя сборку релиза, я не вижу экземпляров A в куче при проверке его с помощью SOS.

Чтобы убедиться в этом, скачайте WinDbg. Затем присоединитесь к вашему процессу и загрузите SOS.

.loadby sos clr

Вы можете сбросить всю кучу, используя !dumpheap -stat или просто тип, используя !dumpheap -type GCTest.A.

Вы должны видеть, как экземпляры растут по мере их создания. Как только GC восстановил экземпляры, вы не должны видеть никаких экземпляров A в куче.

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

0:001> !dumpheap -type GCTest.A
 Address       MT     Size

Statistics:
      MT    Count    TotalSize Class Name
Total 0 objects
  • 1
    Это действительно ожидаемое поведение. Скорее всего, использование инструментов диагностики в VS переводит JIT в режим отладки.
  • 1
    @KonradKokosa это может быть. Я просто хотел сказать, что это, вероятно, проблема с инструментами. PS: Приятно познакомиться, и я с нетерпением жду чтения вашей книги :)
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню