2016-07-22 4 views
2

особенно когда нет прямой ссылки Ссылка на него.Почему сборщик мусора не собирает объекты Задачи

Я думал, что GC продумал все .net темы, чтобы найти ссылки ... Он проверяет ссылки в других местах тоже?

РЕДАКТИРОВАТЬ: Пример экземпляра Давайте представим, что мы находимся в консольном приложении, главный вызов метода, который создает локальную задачу1, затем применяет task1.ContinueWith (task2) и возвращается к main, main do console.readline().

На данный момент это может быть так, что task1 завершен, task2 все еще не запускает GC, который может запускаться, и ни один поток не имеет ссылки на task2. Почему task2 не получает GC'ed?

EDIT2: Возможно, я не использую правильные слова, говоря «задачу»

using System; 
using System.Runtime.InteropServices; 
using System.Threading; 
using System.Threading.Tasks; 

namespace ConsoleApplication 
{ 
    class Program 
    { 
     static void Launch() 
     { 
      var task1 = Task.Run(() => Thread.Sleep(60000)) 
      task1.ContinueWith(() => WriteToFile("Hi")); 
     } 

     static void Main(string[] args) 
     { 
      Launch(); 
      //At this point if a GC occurs which thread or static file has a reference to "()=>WriteTofile("Hi")" ? 
      Console.ReadLine(); 
     } 

Существует основной поток ждет консоли, одна нити (может быть от ThreadPool) работает в спящем режиме. Как только сон закончится, и до начала потока WriteToFile, GC может произойти, не так ли?

+0

Не могли бы вы показать проблему, используя какой-то фактический код? Предполагая, что 'task1' и' task2' являются 'Task', 'task1.ContinueWith (task2)' не будет компилироваться. – svick

+0

Ваше предположение о том, что «все еще не запущено», является допустимым сценарием, просто неверно, task2 запускается * немедленно * после завершения задачи1. Если threadpool работает медленно, это все равно не имеет значения, поскольку очередь threadpool имеет ссылку на него. Обратите внимание, что аргумент * task * передается в [этот код] (http://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/ThreadPoolTaskScheduler.cs,33cd274e06874569). –

+0

У меня нет кода. Это просто теоретически. Что касается очереди threadpool, не все задачи выполняются threadpool, не так ли? В какой момент task2 получает ссылку на очередь threadpool? – Eduard

ответ

3

Ссылается ссылка на task1by the default task scheduler, (Планировщик задач по умолчанию is static).

Продолжение is kept alive by task1 до тех пор, пока оно не будет передано ему назначенному планировщику задач (TaskScheduler.Current на момент создания по умолчанию).

(Обратите внимание, это, вероятно, не единственные возможные корни, только те, которые я быстро обнаружил, глядя через источник)

+0

Ups ... Я забыл рассмотреть статические ссылки для GC-корней :(. – Eduard

+0

Но task1 может быть выставлен в defaultTask Scheduler, по умолчанию taskcheduler может быть изменен, продолжение может быть выделено новому планировщику задач, а затем снова изменить планировщик заданий по умолчанию – Eduard

+0

task1 имеет ссылку на все его продолжения. Даже если планировщик, в котором было задано продолжение задачи, был «мертвым», у вас все еще есть ссылка из 'task1'. –

1

Я подозреваю, что часть вашего непонимания не в том, что нет причины, что код, который вы написанная будет запускать сборку мусора. Вы говорите «сразу после сна ... GC может произойти [?]», Но на самом деле нет: сборщик мусора не будет запускаться просто потому, что ничего не происходит.

Автоматическая сборка мусора в .NET происходит, когда вы выделяете памяти. То есть: когда вы оцениваете выражение, и это значение записывается в память. Сбор мусора применяется только к куче, так как обычно GC запускается, когда вы создаете экземпляр класса, вызывая конструктор.

Даже тогда сборка мусора произойдет только в том случае, если в генерации 0 недостаточно свободной памяти для хранения вновь созданного объекта (и даже тогда, если объект не настолько велик, что он идет прямо в Большой объект Heap).

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

+0

Код, который я предоставил, - всего лишь скелет. Скажем, в самом начале я запускаю другой поток, который constinuosly выделяет новые объекты ... Или перед вызовом Console.ReadLIne Я сплю некоторое время и запустил GC.Colect – Eduard

+0

Ну, если вы разместите более конкретный код, мы могли бы дать более конкретный ответ. Если вы вручную вызываете GC, тогда должен быть корень где-нибудь (как это было предложено в ответе Скотта), - но вы не объяснили это в своем вопросе. –

+0

Спасибо за ответ. Мой английский плохой, и часто я не могу задать правильный вопрос. Я искал корни в этом конкретном случае. – Eduard