Когда массив подлежит сборке мусора? - PullRequest
0 голосов
/ 08 ноября 2018

Несколько лет назад я прочитал книгу CLR через C #, а на днях меня спросили, является ли массив и все еще немного озадаченным, вопрос состоял в том, чтобы выяснить, когда массив в методе ниже доступен для сборки мусора :

public static double ThingRatio()
{
    var input = new [] { 1, 1, 2 ,3, 5 ,8 };
    var count = input.Length;
    // Let's suppose that the line below is the last use of the array input
    var thingCount = CountThings(input);
    input = null;
    return (double)thingCount / count;
}

Согласно ответу, приведенному здесь: Когда объект подвергается сборке мусора? , который гласит:

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

Я бы сказал, что начиная со строки 6 (т.е. input = null;) массив становится объектом GC, но я не уверен ... (я имею в виду, что массив, вероятно, больше не нужен после присваивания, но также изо всех сил, что это после вызова CountThings, но в то же время массив "необходим" для нулевого присваивания).

Ответы [ 3 ]

0 голосов
/ 08 ноября 2018

Миф о ГХ: установка ссылки на объект на ноль заставит ГХ сразу его забрать.
GC Truth: установка ссылки на объект на null иногда позволяет GC собирать его раньше.

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

JIT обычно достаточно умен, чтобы понять, что input = null можно оптимизировать. Это оставляет CountThings(input) в качестве последней ссылки на объект. Поэтому после этого вызова input больше не используется и удаляется как корень GC. В результате объект в памяти теряется (нет ссылок на него), что делает его пригодным для сбора. Когда GC на самом деле собирается собирать его, это другой вопрос.

Дополнительную информацию можно найти по адресу В ноль или в ноль

0 голосов
/ 08 ноября 2018

Ни один объект не может быть собран мусором, пока он распознается как существующий. Объект будет существовать в .NET до тех пор, пока существует какая-либо ссылка на него или у него есть зарегистрированный финализатор, и он перестанет существовать, когда ни одно из условий не будет применено. Ссылки в объектах будут существовать до тех пор, пока существуют сами объекты, а ссылки в автоматических переменных будут существовать до тех пор, пока существуют какие-либо средства, с помощью которых они будут наблюдаться. Если сборщик мусора обнаружит, что единственные ссылки на объект без зарегистрированного финализатора содержатся в слабых ссылках, эти ссылки будут уничтожены, что приведет к прекращению существования объекта. Если сборщик мусора обнаруживает, что единственные ссылки на объект с зарегистрированным финализатором хранятся в слабых ссылках, то любые слабые ссылки, свойство «воскресение трека» которых имеет значение false, ссылка на объект будет помещена в строго укоренившийся список объектов. нуждающихся в «немедленной» финализации, и финализатор будет незарегистрирован (что позволит ему прекратить свое существование, если и когда финализатор достигнет точки выполнения, где вообще не будет никакой ссылки на объект).

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

В вашем примере есть три сценария, которые могут применяться в зависимости от того, что CountThings делает с переданной ссылкой:

  1. Если CountThings нигде не хранит копию ссылки, или любые копии ссылок, которые он хранит, перезаписываются до того, как перезаписывается input, то он прекращает свое существование, как только input перезаписывается или перестает существовать [переменные автоматической продолжительности могут перестать существовать каждый раз, когда компилятор определяет, что их значение больше не будет соблюдаться].

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

  3. Если последняя существующая ссылка, массив в конечном итоге удерживается в слабой ссылке, массив будет продолжать существовать до первого цикла GC, где это имеет место, после чего слабая ссылка будет очищена, вызывая массив перестать существовать. Обратите внимание, что отсутствие неслабых ссылок на массив будет актуально только тогда, когда происходит цикл GC. Для программы возможно (и не очень редко) сохранять копию ссылки в WeakReference, ConditionalWeakTable или другом объекте, содержащем некоторую форму слабой ссылки, уничтожать все другие копии, а затем считывать слабую ссылка для создания неслабой копии ссылки до следующего цикла GC. Если это произойдет, система не будет ни знать, ни заботиться о том, что было время, когда существовали неслабые копии ссылки. Однако, если цикл GC происходит до того, как ссылка будет считана, тогда код, который позже исследует слабую ссылку, найдет ее пустой.

Ключевое наблюдение заключается в том, что, хотя финализаторы и слабые ссылки немного усложняют ситуацию, единственный способ, которым GC уничтожает объекты, заключается в недействительности слабых форм ссылок. Что касается GC, то единственными типами хранилищ, которые существуют, когда система фактически не выполняет цикл GC, являются те, которые используются существующими объектами, те, которые используются для внутренних целей .NET, и области хранения, которые доступны для удовлетворить будущие ассигнования. Если объект создан, занимаемое им хранилище перестает быть областью хранилища, доступной для будущих выделений. Если впоследствии объект перестает существовать, хранилище , в котором содержался объект, также прекращает существовать в любой форме, о которой GC знает до следующего цикла GC. Следующий цикл GC не уничтожит объект (который уже прекратил свое существование), но вместо этого добавит хранилище, в котором он находился, обратно в список областей, доступных для добавления будущих выделений (в результате чего это хранилище снова будет существовать) .

0 голосов
/ 08 ноября 2018

Помните, что объекты и переменные не одно и то же. переменная имеет область действия для конкретного метода или типа, но объект, на который он ссылается или на который ссылается, не имеет такого понятия; это просто капля памяти. Если GC запускается после input = null;, но до конца метода, массив является просто еще одним потерянным объектом. Это не достижимо , и, следовательно, имеет право на сбор.

И ключевое слово здесь - «достижимый» (а не «необходимый»). Объект массива больше не нужен после этой строки: var thingCount = CountThings(input);. Тем не менее, он все еще доступен и поэтому не может быть собран в этот момент ...

Мы также должны помнить, что это не собрано сразу. Только имеет право быть собранным. С практической точки зрения, я обнаружил, что среда выполнения .Net не склонна вызывать GC в середине пользовательского метода, если в этом нет необходимости. Вообще говоря, необязательно или полезно устанавливать переменные на null рано, и в некоторых редких случаях может быть даже вредным.

Наконец, я добавлю, что код, который мы читаем и пишем, - это не тот код, который фактически используется машиной. Помните, что есть также шаг компиляции, чтобы перевести все это на IL, а затем процесс JIT для создания окончательного машинного кода, который действительно выполняется. Даже концепция следующей строки - это уже абстракция от того, что на самом деле происходит. Одна строка может быть расширена до нескольких строк фактического IL, а в некоторых случаях даже может быть переписана для включения всех новых типов, сгенерированных компилятором, как с замыканиями или блоками итераторов. Так что все здесь на самом деле относится только к простому случаю.

...