将净垃圾收集,这不是引用的对象,但有一个线程在做什么工作?(Will .Net Garbage Co

2019-06-24 01:11发布

我有以下代码(上剪下来的可读性):

主类:

public StartProcess()
{
    Thinker th = new Thinker();
    th.DoneThinking += new Thinker.ProcessingFinished(ThinkerFinished);
    th.StartThinking();
}

void ThinkerFinished()
{
    Console.WriteLine("Thinker finished");
}

思想家类:

public class Thinker
{
    private System.Timers.Timer t;

    public delegate void ProcessingFinished();
    public event ProcessingFinished DoneThinking;

    BackgroundWorker backgroundThread;

    public Thinker() { }

    public StartThinking()
    {
        t = new System.Timers.Timer(5000);    // 5 second timer
        t.AutoReset = false;
        t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
        t.Start();

        // start a background thread to do the thinking
        backgroundThread = new BackgroundWorker();
        backgroundThread.DoWork += new DoWorkEventHandler(BgThread_DoWork);
        backgroundThread.RunWorkerAsync();
    }

    void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        DoneThinking();
    }

    BgThread_DoWork(object sender, DoWorkEventArgs e)
    {
        // work in here should go for much less than 5 seconds
        // it will die if it doesn't

        t.Stop();
        DoneThinking();
    }
}

我原本预计要发生的是,在主类的事件处理程序将阻止垃圾收集的思想家。

显然,这并非如此 。

现在我想知道垃圾回收是否会不管线程是否是“忙”或不发生。 换句话说,有没有它会被垃圾收集5秒超时到期前的机会吗?

换一种方式,有可能是它的处理完毕的垃圾收集器收集我的思想家?

Answer 1:

不,一个线程,只要它被引用考虑现场,并运行任何线程被认为是引用(IIRC正在运行的线程注册其堆栈作为GC根,以及堆栈将引用线程)。

这就是说我在看你的榜样,我不明白的地方,你认为一个线程被催生?



Answer 2:

不,正在运行的线程的堆栈充当GC目的的根源。 作为线程运行堆栈会万岁,那么线程本身将不会被收集,只要它的运行。

这里有一个文章是提到(除其他事项外)什么的根源是GC的目的。 为了节省时间,GC根是全局对象,静态对象,所有线程堆栈的所有参考,并包含引用了所有CPU寄存器。



Answer 3:

你的问题是有点难以回答。 乔尔一样,据我所知,你有堆栈引用您的计时器,它本身是引用该线程的唯一的事情就没事。 鉴于此,人们所期望的思想家实例可以被收集。

我很好奇这一点,需要对可能发生的事情更具体的解释,所以我挖成反射了一下。 事实证明,System.Timers.Timer最终创建一个System.Threading.Timer,其在内部创建TimerBase,内部类的实例。 TimerBase从CriticalFinalizerObject,这是确保了Constrained执行区域(CER)所有的代码将执行之前实现类完全完成并通过GC丢弃的系统类型派生的。 TimerBase也是IDisposable接口,它的Dispose方法循环和spinwaits直到锁被释放。 在这一点上,我开始跑步到外部代码,所以我不是很确定的锁是如何初始化或释放。

然而,根据该TimerBase类是如何写的,事实上,它从CriticalFinalizerObject派生,而事实上,其dispose spinwaits直到锁被释放,我认为其安全地说,不是由任何引用的线程不会敲定,直到代码执行完毕。 也就是说......要注意,它很可能会被GC处理......这是很重要的很可能不止一次,如最终确定可以大大延长上完成对象集合的过程。 对于那些CriticalFinalizerObjects,最终处理的可能,如果有积极的CER是确保将全面执行执行代码需要更长的时间。

这可能意味着你有完全相反的问题,如果您的思想家需要一段时间来执行。 而不是收集这些对象过早,他们将进入一个漫长的定稿,以及任何他们参考的Gen2结束了,生活很长一段时间,直到GC终于能够充分收集它们。



Answer 4:

如果我读这一权利(和我可以在这里下车的方式),它可以收集,因为它目前没有做任何事情。

如果你有在你的启动方法的局部变量,并且该方法仍然活跃,这些变量仍然是“范围内”在堆栈上,并为您提供螺纹根。 但是,你使用的唯一变量是你的私人定时器,因为这是自己为根与线程和线程堆栈上什么都没有,什么都不剩让它活着。



Answer 5:

我同意不同意和,如果参考线程对象丢失该线程将被终止并收集垃圾。 根据你的情况,因为它不直接使用线程并使用定时器它可能不是这样。 但是,如果你曾要求在一个线程和线程引用的方法与方法的末尾,则它会被GC收集丢失



文章来源: Will .Net Garbage Collect an object that's not referenced, but has a thread that's doing work?