Какие из этих объектов имеют право на сборку мусора? - PullRequest
12 голосов
/ 20 ноября 2011

Это вопрос, который мне задавали во время моего интервью: Какой «случайный» объект (ы) будет получен во время вызова «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 и соответствующей семантики слабых ссылок.Насколько я знаю, спецификация C # не дает точного описания того, что GC.Collect должен делать и как обрабатывать слабые ссылки.

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

Ответы [ 4 ]

13 голосов
/ 20 ноября 2011

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

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

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

9 голосов
/ 20 ноября 2011

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

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

3 голосов
/ 06 января 2013

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

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

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

1 голос
/ 20 ноября 2011

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

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

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

...