为什么垃圾收集器不收集Tasks对象

时间:2016-07-22 16:13:01

标签: .net garbage-collection task-parallel-library

特别是当没有活动线程引用它时。

我认为GC认为所有的.net线程都能找到引用...它是否也检查了其他地方的引用?

编辑:实例让我们假设我们在一个控制台应用程序中,主要调用一个创建本地task1的方法,然后应用task1.ContinueWith(task2)并返回main,main执行console.readline()。 / p>

此时可能是task1已经完成,task2仍然没有启动GC可以启动,没有线程有对task2的引用。为什么task2没有得到GC?

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();
        }

主线程正在等待控制台,一个线程(可能来自线程池)运行Sleep。在Sleep完成之后,在WriteToFile线程启动之前,可能会发生GC,不是吗?

2 个答案:

答案 0 :(得分:3)

task1的引用被保留by the default task scheduler,(默认任务调度程序is static)。

继续is kept alive by task1,直到它被移交给它,默认情况下分配了任务调度程序(TaskScheduler.Current)。

(注意,这些可能不是唯一可能的根,只是我很快找到通过源查找的根)

答案 1 :(得分:1)

我怀疑你的一部分误解是没有理由你编写的代码会运行垃圾收集。你说“就在睡眠之后......一个GC可能会发生[?]”但实际上,没有:垃圾收集器不会因为没有发生任何事情而无法运行。

当您分配内存时,会发生.NET中的自动垃圾回收。即:当您评估表达式并将该值写入内存时。垃圾收集仅适用于堆,因此通常通过调用构造函数创建类的实例时会触发GC。

即使这样,只有在第0代没有足够的可用内存来存储新创建的对象时才会发生垃圾收集(即使这样,假设对象不是那么大,它直接进入大对象堆) )。

考虑到这一点,您发布的代码没有分配足够的内存来触发GC,因此我不希望在程序终止之前收集在那里创建的任何对象。