финализатор не вызывается после GC.Collect () [дубликат]
Я думаю, что упускаю что-то фундаментальное, и надеюсь, что вы можете помочь. Код ниже создает объект, удаляет ссылку и вызывает сборщик мусора. Я ожидал, что финализатор SomeClass будет вызываться при нахождении в Readline. Это не так. Я пробовал вызывать GC.Collect в цикле, добавляя несколько вызовов Sleep () для запуска потока финализатора. Не бывает.
Только когда Main заканчивается, финализатор попадает, но, что удивительно, ударяется дважды. Что мне не хватает?
class Program
{
public static void Main(string[] args)
{
SomeClass some = new SomeClass("Hello World!");
some = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Done");
Console.ReadLine();
}
}
class SomeClass
{
string ss;
public SomeClass(string s) { ss = s; }
~SomeClass()
{
var hash = this.GetHashCode();
}
}
Дополнение Существует разница в запуске программы в режиме отладки и в режиме выпуска. Приведенная ниже программа работает в режиме отладки, Start - Done - Finalize
тогда как в режиме выпуска отображается файл журнала Start - Finalize - Done
. Последнее - то, что я ожидал.
class Program
{
private static string logfile = @"c:\temp\log.txt";
public static void Main(string[] args)
{
File.WriteAllText(logfile, "Start\n");
SomeClass some = new SomeClass("Hello World!");
some = null;
GC.Collect();
GC.WaitForPendingFinalizers();
File.AppendAllText(logfile, "Done\n");
}
}
class SomeClass
{
private static string logfile = @"c:\temp\log.txt";
public string SomeString { get; set; }
public SomeClass(string s) { SomeString = s; }
~SomeClass()
{
File.AppendAllText(logfile, "Finalize\n");
}
}
Ответы
Объекты, которые собираются сборщиком мусора, становятся пригодными для финализации и помещаются в очередь финализации. Нет абсолютно никакой гарантии, что эти финализаторы когда-либо будут запущены .
Я собираюсь перенаправить вас на замечательные посты Эрика Липперта по этому поводу с подходящим названием «Когда все, что вы знаете, неправильно». В частности:
Миф: Установка переменной в значение null приводит к запуску финализатора на объекте, на который ранее ссылалась переменная. Установка переменной в значение null не приводит к немедленному выполнению каких-либо действий, кроме изменения значения переменной. Если переменная была последней живой ссылкой на рассматриваемый объект, то этот факт будет обнаружен, когда сборщик мусора запустит сборщик для любого поколения, в котором находился объект. (Если он запускается вообще, что может и не быть. Нет никаких гарантий что GC работает.)
И даже с GC.Collect()
:
Миф: вызов
GC.Collect()
вызывает запуск финализаторов. Нет, это вызывает сбор. Это может идентифицировать объекты, которые являются кандидатами на финализацию, но не заставляет планировать поток финализатора. Если это то, что вы хотите - только для тестирования! - тогда звониGC.WaitForPendingFinalizers()
.
Так что лучший шанс на успех - у GC.WaitForPendingFinalizers()
. Но даже тогда, ссылаясь на остальную часть сообщения ( и его продолжение ), ЗАПУСК ФИНАЛИЗАТОРА НЕ ГАРАНТИРУЕТСЯ . Не полагайтесь на это.
Я написал более подробное объяснение этого вопроса, чтобы вы могли использовать его в качестве отправной точки для дальнейших исследований.