特别是当没有活动线程引用它时。
我认为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,不是吗?
答案 0 :(得分:3)
task1
的引用被保留by the default task scheduler,(默认任务调度程序is static)。
继续is kept alive by task1
,直到它被移交给它,默认情况下分配了任务调度程序(TaskScheduler.Current
)。
(注意,这些可能不是唯一可能的根,只是我很快找到通过源查找的根)
答案 1 :(得分:1)
我怀疑你的一部分误解是没有理由你编写的代码会运行垃圾收集。你说“就在睡眠之后......一个GC可能会发生[?]”但实际上,没有:垃圾收集器不会因为没有发生任何事情而无法运行。
当您分配内存时,会发生.NET中的自动垃圾回收。即:当您评估表达式并将该值写入内存时。垃圾收集仅适用于堆,因此通常通过调用构造函数创建类的实例时会触发GC。
即使这样,只有在第0代没有足够的可用内存来存储新创建的对象时才会发生垃圾收集(即使这样,假设对象不是那么大,它直接进入大对象堆) )。
考虑到这一点,您发布的代码没有分配足够的内存来触发GC,因此我不希望在程序终止之前收集在那里创建的任何对象。