System. Windows .Forms.Timer и сборка мусора с C# - PullRequest
0 голосов
/ 28 мая 2020

Если я создаю System. Windows .Forms.Timer, который не связан с файлом Form.Designer.cs (например, я просто создаю экземпляр таймера в любом месте своего кода), и я создаю System.ComponentModel. Компонент контейнера и создайте элемент управления для добавления к нему, скажем, NotifyIcon (этот notifyIcon не будет иметь связанного с ним значка) и добавьте этот notifyIcon в объект моих компонентов ЗАТЕМ создайте экземпляр forms.timer с компонентом в качестве параметра для конструктора таймера , будет ли таймер когда-либо G C -ed, если для свойства enabled таймеров было установлено значение false в течение времени жизни программы, И таймер никогда не был удален в течение времени жизни программы? Или, если этот компонент не утилизируется напрямую, будет ли таймер защищен от сборки мусора?

Вот пример кода:

NotifyIcon notifyIcon = new NotifyIcon();
notifyIcon.Visible = false;
System.ComponentModel.IContainer components = new System.ComponentModel.Container();
components.add(notifyIcon);
System.Windows.Forms.Timer formTimer = new System.Windows.Forms.Timer(components);
formTimer.Enabled = true;
formTimer.Enabled = false;

Спасибо за чтение

1 Ответ

1 голос
/ 28 мая 2020

Теория

Если объект A содержит ссылку на объект B, и вы присваиваете значение A null, то через некоторое время A будет удален сборщиком мусора. если есть еще другие, ссылающиеся на B, то B не является сборщиком мусора. Однако, если A был последним со ссылкой на B, то B также будет собран:

Person Joseph = new Person
{
    Id = 1, 
    Address = new Address {Id = 10, ...},
    ...
};

Joseph.Address = new Address {Id = 11, ...}

Через некоторое время Адрес с Id 10 будет удален, потому что никто не имеет ссылки на него anymore.

Person Mary = new Person
{
    Id = 2, 
    Address = Joseph.Address,
    ...
};
Joseph = null;

Через некоторое время Человек с Id 1 будет удален, потому что никто больше не имеет на него ссылки. Однако адрес с идентификатором 11 не будет собираться в мусор, потому что человек с идентификатором 2 содержит ссылку на него.

mary = null;

Теперь никто не имеет ссылки на адрес с идентификатором 11, поэтому он будет быть сборщиком мусора.

Обратно к вашему вопросу

  • Вы создаете новый объект-контейнер
  • Вы создаете новый объект NotifyIcon.
  • Вы добавляете этот объект NotifyIcon к объекту компонентов
  • Вы создаете новые объекты Timer, используя конструктор, который приказывает таймеру добавить себя в контейнер.

Таким образом, объект контейнера имеет ссылки на как созданные объекты NotifyIcon и Timer. Пока эти объекты не удалены из контейнера, и контейнер не удален и не собран мусором, этот контейнер будет содержать эти ссылки, и, следовательно, ни notifyIcon, ни таймер не будут собраны мусором.

components.Dispose();

Согласно справочному источнику System.ComponentModels.Container , это будет делать следующее:

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        lock (syncObj) {
        while (siteCount > 0)
        {
            ISite site = sites[--siteCount];
            site.Component.Site = null;
            site.Component.Dispose();
        }
        sites = null;
        components = null;
    }
}

Итак, Container.Dispose() вызовет Dispose() всех добавленных компонентов, а затем освободит ссылка на добавленные компоненты.

  • Если у вас есть ссылки на эти компоненты в другом месте, то эти компоненты не будут собираться сборщиком мусора. Однако, поскольку они утилизированы, обычно их нельзя использовать.
  • Если контейнер был единственным со ссылками, то после Container.Dispose() NotifyIcon и таймер могут быть собраны.
  • Поскольку у вас все еще есть ссылка на Контейнер, сам Контейнер не собирается. Поскольку он удален, Контейнер больше не может использоваться.
  • Чтобы убедиться, что Контейнер собран, либо выведите ссылку go за пределы области видимости, либо присвойте ей значение null.

В каждом Form.Dispose() вы найдете код, похожий на:

private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
    if (disposing && (components != null))
    {
        components.Dispose();
    }
    base.Dispose(disposing);
}

Когда форма удаляется, this.components также удаляется, что означает, что все IComponents, которые он содержит, удаляются, а ссылки удалены. Даже ссылка на Container.ComponentCollection удалена. Обратите внимание, что форма по-прежнему содержит ссылку на this.components, поэтому, хотя this.components больше не может использоваться.

Последнее немного странно: если вы больше не храните ссылки на свой NotifyIcon / Timer они собираются мусором, однако this.Components - нет, пока существует форма. Было бы лучше, если бы Form.Dispose также выпустил ссылку на this.components

...