Я читал "CLR через С#", и кажется, что в этом примере объект, который был первоначально назначен "obj", будет иметь право на сборку мусора после выполнения строки 1, а не после строки 2.
void Foo()
{
Object obj = new Object();
obj = null;
}
Это потому, что срок жизни локальной переменной определен не по объему, в котором он был определен, но в последний раз, когда вы его прочитали.
Итак, мой вопрос: как насчет Java? Я написал эту программу, чтобы проверить такое поведение, и похоже, что объект остается в живых. Я не думаю, что JVM может ограничить время жизни переменной при интерпретации байт-кода, поэтому я попытался запустить программу с помощью java -Xcomp для принудительной компиляции методов, но "финализировать" все равно не вызывается. Похоже, что это не так для Java, но я надеюсь, что получу более точный ответ. Также, как насчет Android Dalvik VM?
class TestProgram {
public static void main(String[] args) {
TestProgram ref = new TestProgram();
System.gc();
}
@Override
protected void finalize() {
System.out.println("finalized");
}
}
Добавлено: Джеффри Рихтер дает пример кода в "CLR через С#", примерно так:
public static void Main (string[] args)
{
var timer = new Timer(TimerCallback, null, 0, 1000); // call every second
Console.ReadLine();
}
public static void TimerCallback(Object o)
{
Console.WriteLine("Callback!");
GC.Collect();
}
TimerCallback вызывается только один раз на MS.Net, если целью проекта является "Release" (таймер уничтожается после вызова GC.Collect()) и вызывается каждую секунду, если целью является "Debug" (продолжительность жизни переменных увеличивается, поскольку программист может попытаться получить доступ объект с отладчиком). Но на Mono callback вызывали каждую секунду независимо от того, как вы его компилируете. Похоже, реализация Mono 'Timer' хранит ссылку на экземпляр где-то в пуле потоков. Реализация MS не делает этого.