Сборка мусора объекта, содержащего поток с циклом infinte - PullRequest
3 голосов
/ 21 ноября 2011

Допустим, у меня есть класс, который делает что-то вроде:

 public class Foo
 {
     private bool _forceStop = false;
     private Queue<object> queue;
     private void ProcessInBackground()
     {
          while(!forceStop )
          {
              Moniter.Enter(queue);
              while(!_forceStop && queue.Count == 0)Moniter.Wait(queue);
              object data = null;                 
              if (!_forceStop)
                 data = queue.Dequeue(); 
              Moniter.Exit(queue);

              if (data != null)
                 processData(data);
           }
      }

      ...
  }

Если объект класса Foo больше не используется и для _forceStop никогда не устанавливается значение true в этом объекте и предполагается, что ProcessInBackground былназывается, будет ли он собран?

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

Ответы [ 4 ]

5 голосов
/ 21 ноября 2011

(Как и Марк, я предполагаю, что вы имеете в виду объект, для которого вы назвали ProcessInBackground. Я также предполагаю, что queue - это поле.)

Нет - вы 'мы по-прежнему ссылаемся на queue, что означает, что поле в объекте будет прочитано, что означает, что содержащийся объект не может быть собран мусором.

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

using System;
using System.Threading;

public class OddFinalizer   
{
    int field;

    public OddFinalizer(int field)
    {
        this.field = field;
    }

    ~OddFinalizer()
    {
        Console.WriteLine("OddFinalizer");
    }

    public void Work()
    {
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine("In loop before last access...");
            GC.Collect();
            GC.WaitForPendingFinalizers();            
            Thread.Sleep(1000);
        }
        Console.WriteLine("Field value: {0}", field);
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine("In loop after last access...");
            GC.Collect();
            GC.WaitForPendingFinalizers();
            Thread.Sleep(1000);
        }
    }

    static void Main(string[] args)
    {
        new OddFinalizer(10).Work();
    }
}

Результаты (скомпилированы с / o +, , а не запускаются в отладчике):

In loop before last access..
In loop before last access..
In loop before last access..
In loop before last access..
In loop before last access..
Field value: 10
In loop after last access...
OddFinalizer
In loop after last access...
In loop after last access...
In loop after last access...
In loop after last access...
3 голосов
/ 21 ноября 2011

Да, object data будет собрано (при условии, что processData() не внесет его в список). GC может обрабатывать (управляемые) потоки, если бы он не смог, мир закончился бы.

Но ваш код не поточно-ориентированный, ваш запрос после того, как вы сняли блокировку.

Предложение по улучшению:

//untested
private bool _forceStop = false;
private object _locker = new object();  // better not depend on queue here

private void ProcessInBackground()
{
    while(true)
    {
       // Moniter.Enter(queue);
       lock(_locker)
       {       
          while(!_forceStop && queue.Count == 0)
            Moniter.Wait(_locker);

          //Moniter.Exit(queue);
          if (_forceStop) break;

          object data = queue.Dequeue(); 
       }
       processData(data);
    }
}

Редактировать:

При втором чтении речь идет о вмещающем объекте. Который, конечно, хранится в потоке.

1 голос
/ 21 ноября 2011

и _forceStop никогда не устанавливается в значение true, будет ли объект собираться?

Нет.

Объект не может быть собран мусором, пока один из его методовнаходится на стеке вызовов потока.В стеке вызовов есть ссылка на объект.

В этом случае ProcessInBackground - это метод в стеке вызовов потока.


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

В моем собственном коде у меня нетфинализаторы.У меня есть несколько предметов, которые меня волнуют, когда их собирают.Когда я ожидаю, что они будут собраны, они не будут в стеке вызовов в этот момент.Если они собираются, когда они находятся в стеке вызовов, потому что .net считает, что это хорошо, я не проблема.

Я не думаю, что эта деталь изменит то, как я должен писать какой-либо код, поэтому я 'Я собираюсь продолжить писать код, как если бы мой неверный факт, приведенный выше, был правдой, хотя и немного помнил о его неправильности.Если моя ситуация схожа с вашей, вы тоже можете это сделать.

1 голос
/ 21 ноября 2011

Предполагая, что под "объектом" вы подразумеваете экземпляр, которому принадлежит метод, затем, если поток выполняет метод ProcessInBackground, тогда этот экземпляр внедряется потоком (это arg0, и вы используете поля из него впетля).Так что нет, оно не будет собрано.

Если в качестве «объекта» вы подразумеваете «данные», то все, кроме самых последних, , безусловно, имеют право.Самая последняя версия может зависеть от конфигурации компилятора (он исключил локальный?) И CLI (проверяет ли локальные объекты, которые не читаются?).Я бы сказал: «Вероятно, он будет подходящим, в версии / оптимизирован; вероятно, не в отладке / неоптимизирован».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...