Member 14741901 Ответов: 2

Объект не освобождается без привязки к таймеру


public class Program
    {
        
        public static void Main(string[] args)
        {
            object obj = new ObjectWithTimer();
            Console.ReadLine();
            Console.WriteLine("obj=null");
            obj = null;
            Console.ReadLine();
        }
    }

    public class ObjectWithTimer
    {
        private int i;
        public System.Timers.Timer t;
        public ObjectWithTimer()
        {
            t = new System.Timers.Timer(5000);
            t.Elapsed += Obj_Elapsed;
            t.Enabled = true;
        }

        public void Obj_Elapsed(object sender, ElapsedEventArgs e)
        {
            i++;
            Console.WriteLine(i);
        }
    }


Что я уже пробовал:

Hi all, 
Please see example below. Even though the reference to obj is set to null, the obj is not released and Obj_Elapsed continues printing i. Notice there is no reference to the timer out of the scope of the ObjectWithTimer constructor.

2 Ответов

Рейтинг:
1

OriginalGriff

Переменные-это не то же самое, что экземпляр, который они содержат: просто установка переменной в null не изменяет объект, на который она раньше "указывала", и это никоим образом не означает, что система немедленно уничтожит (или даже начнет процесс уничтожения) сам объект.

Подумайте об этом с точки зрения автомобилей: у вас есть автомобиль. Вы кладете свой мобильный телефон в бардачок и продаете машину. Новый владелец уезжает в закат на своей новой машине.
Где твой мобильный телефон?

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

Когда вы устанавливаете таймер он работает до тех пор пока все ссылки на него не исчезнут, и система получает так мало памяти, что сборщик мусора начинает действовать, чтобы решить, что утилизировать.
Вы хотите остановить таймер? Сделать это:

Console.WriteLine("obj=null");
obj.t.Enabled = false;
obj = null;
Console.ReadLine();


phil.o

Что случилось с пиджаком и ручкой? :)

OriginalGriff

Это рубашка другого цвета! ;)

Рейтинг:
0

George Swan

Если ваш класс использует объект, который реализует IDisposable, так как Timer делает, вы должны реализовать IDisposable в вашем классе. Затем вы можете поместить свой класс в пределах a using заявление так что Dispose вызывается, когда он выходит за пределы области действия и когда возникает исключение. Кроме того, вам не будет разрешено переназначить экземпляр класса в пределах using заблокируйте его, и ваша ошибка будет отмечена компилятором.


static async Task Main()
       {

           {
               using ObjectWithTimer owt = new ObjectWithTimer();
               Console.ReadLine();
           }
           Console.WriteLine("Exited using's scope. Timer disposed.");
           Console.ReadLine();
       }
public sealed  class ObjectWithTimer : IDisposable
   {
       private int i;
       public Timer timer;
       public ObjectWithTimer()
       {
           timer = new Timer(2000);
           timer.Elapsed += TimerElapsed;
           timer.Enabled = true;
       }

       public void TimerElapsed(object sender, ElapsedEventArgs e)
       {
           i++;
           Console.WriteLine(i);
       }

       public void Dispose()
       {

           timer.Dispose();

       }
   }