Подтвердить что ты не робот

Какие из этих объектов имеют право на сбор мусора?

Это вопрос, который меня недавно задали в моем интервью: Какие "случайные" объекты будут собираться во время вызова "GC.Collect()"

String a = new Random().Next(0, 1) ==1 ? "Whatever 1" : "Whatever 2";

String b = new WeakReference(new Random()).Target.Next(0, 1) == 1 ?
    "Whatever 1" : "Whatever 2";

GC.Collect();

Я ответил, что это вопрос, специфичный для реализации, и он сильно зависит от реализации GC и соответствующей слабой ссылочной семантики. Насколько я знаю, спецификация С# не дает точного описания того, что должен делать GC.Collect и как следует обрабатывать слабые ссылки.

Однако мой интервьюер хотел услышать что-то еще.

4b9b3361

Ответ 1

Оба экземпляра Random() и WeakReference имеют право на сбор:

  • Первый Random не был сохранен в локальном, а тем более локальном, который позже читается.
  • Второй Random был передан в WeakReference, так что было бы нормально собираться в любом случае, но сам WeakReference не хранится нигде, поэтому он тоже имеет право на сбор.

Ни одна из строк не существует (здесь всего 2 экземпляра строк, а не 4, даже если был достигнут весь возможный путь к коду): поскольку они являются литералами в коде С#, они интернированы после их существования.

Ответ 2

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

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

Ответ 3

Однако мой интервьюер хотел услышать что-то еще.

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

Например, вызов GC.Collect может вызвать оптимизацию хвостового вызова, и в этом случае нет глобальных корней, поэтому все блоки, выделенные кучей, будут собраны. Или компилятор может создать новую запись в фрейме стека для каждого временного (а не только для переменных в исходном коде), который сохраняет все доступное и ничего не собирается. Или компилятор может поменять порядок создания строк a и b и собрать объект Random, на который ссылается WeakReference, до вызова метода Target, вызвавшего исключение ссылки null, так что другой Random никогда не выделяется.

Ответ 4

GC.Collect похож на Java, эквивалентный System.gc()

Он "рекомендует" проверять наличие нулевых значений для их удаления. Вы не можете действительно зависеть от этой функции, поскольку она действительно автоматическая, в отличие от С++.

Надеюсь, что это поможет!