2010-04-30 3 views
1

У меня есть простой класс:Может ли запущенный объект собирать мусор?

public class Runner 
{ 
    public void RunAndForget(RunDelegate method) 
    { 
     ThreadPool.QueueUserWorkItem(new WaitCallback(Run), method); 
    } 

    private void Run(object o) 
    { 
     ((RunDelegate)o).Invoke(); 
    } 
} 

И если я использую это так:

private void RunSomethingASync() 
{ 
    Runner runner = new Runner(); 
    runner.FireAndForget(new RunDelegate(Something)); 
} 

Есть ли опасность его использования, как это? Мои кишки C++ говорят мне, что объект runner должен быть уничтожен после завершения RunSomethingASync. Я прав? Что происходит тогда с методом, запущенным на другом потоке?

Или, может быть, это наоборот, и бегун не будет собран? Это будет проблемой, поскольку я могу многократно вызвать RunSomethingASync().

ответ

8

Мои кишки C++ говорят мне, что объект Runner должен быть уничтожен после завершения RunSomethingASync. Я прав?

Короче говоря, нет. Сборка мусора .NET не выполняется на детерминированной основе. Объект имеет право на сборку мусора, если он уже не укоренен - ​​то есть, когда больше нет ссылок на него (из живых объектов). Нет никакой гарантии, что какой-либо конкретный объект или вообще какой-либо объект вообще будет собирать мусор, хотя это довольно вероятно.

Однако в вашем случае ваш объект даже не имеет права. Хотя объект выходит из сферы действия вашего кода (так что, как представляется, ссылок не существует), делегаты содержат ссылки на свой собственный экземпляр (при условии, что они указывают на метод экземпляра). Ссылка на ваш объект будет существовать до тех пор, пока не вызывается Run, так как ThreadPool удерживает ссылку на делегат до тех пор, и этот делегат имеет ссылку на Runner.

Итак, чтобы ответить на ваш вопрос, нет никакой опасности в том, что вы делаете. Поскольку делегат ссылается на экземпляр, ваш объект не может и не будет собран, пока ваша работа не завершится. Как только он будет завершен, ваш объект будет иметь право на участие.

+0

большое спасибо, очень хороший ответ – Kugel

5

Объект не будет собирать мусор, пока он не будет укоренен, то есть до тех пор, пока все доступные ссылки на него не будут удалены. Существует исключение, если два объекта содержат ссылки друг на друга, и ничто иное не содержит ссылок на эти объекты, эти два объекта доступны для коллекции мусора. Запуск асинхронных методов, таких как ваш, содержит ссылки на объект и не будет использоваться средний вызов.

Примечание к комментарию ниже: Вызов метода Dispose() не приводит к сбору коллекции мусора на этом объекте.

Поскольку мы говорим о Garbage Collection здесь есть ссылка на функцию GC.Collect: http://msdn.microsoft.com/en-us/library/xe0c2357.aspx

и сам GC класс:
http://msdn.microsoft.com/en-us/library/a0fwz4wc(v=VS.100).aspx

EDIT: См ответ Адама о делегатов и ссылки на объекты.

+2

Это не очень полезно. Это хорошо известный факт. В моем случае кто держит ссылку на объект Runner, который я создал? – Kugel

+0

Вызывает ли вызов .Dispose() в сборке мусора с помощью IDisposable? –

+0

@ Нет, это не так. Вы можете вызвать утилизацию объекта и технически сохранить его навсегда. – kemiller2002

0

Нет, объект, где выполняется код, не может быть собран, потому что есть несколько ссылок на объект (например, «this» является ссылкой на объект).

+0

Нет, это неправда. Объект, на который ссылается только сам по себе, недоступен, поэтому его можно собрать. Однако в этом случае ThreadPool может содержать ссылку на объект (через делегата), но я не уверен в этом ... –

+0

@Thomas: Да, в ThreadPool имеется ссылка на делегат, который содержит ссылку на объект. –

+0

@Thomas: Ссылка «this» доступна в стеке текущего метода. Алгоритм очистки работает как с памятью для стека, так и с кучей. – TcKs

Смежные вопросы