假设我有一个类似于:
的课程 public class Foo
{
private bool _forceStop = false;
private Queue<object> queue;
private void ProcessInBackground()
{
while(!forceStop )
{
Moniter.Enter(queue);
while(!_forceStop && queue.Count == 0)Moniter.Wait(queue);
object data = null;
if (!_forceStop)
data = queue.Dequeue();
Moniter.Exit(queue);
if (data != null)
processData(data);
}
}
...
}
如果不再使用Foo类的对象,并且在该对象中_forceStop永远不会设置为true并且假设已调用ProcessInBackground,那么它是否会被收集?
编辑:已解决,歧义增加了线程安全性。对不起,当我编写示例时,我刚刚编写了一个场景。
答案 0 :(得分:5)
(和Marc一样,我假设你指的是你调用ProcessInBackground
的对象。我也假设queue
是一个字段。)
不 - 你仍然指的是queue
,这意味着中的字段将被读取,这意味着包含的对象不能被垃圾收集。
请注意,仅仅因为对象中运行的方法不阻止垃圾收集 - 垃圾收集器只关心是否有可能使用引用本身,或者对象中的字段正在阅读演示代码显示:
using System;
using System.Threading;
public class OddFinalizer
{
int field;
public OddFinalizer(int field)
{
this.field = field;
}
~OddFinalizer()
{
Console.WriteLine("OddFinalizer");
}
public void Work()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("In loop before last access...");
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(1000);
}
Console.WriteLine("Field value: {0}", field);
for (int i = 0; i < 5; i++)
{
Console.WriteLine("In loop after last access...");
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(1000);
}
}
static void Main(string[] args)
{
new OddFinalizer(10).Work();
}
}
结果(使用/ o +编译,不在调试器中运行):
In loop before last access..
In loop before last access..
In loop before last access..
In loop before last access..
In loop before last access..
Field value: 10
In loop after last access...
OddFinalizer
In loop after last access...
In loop after last access...
In loop after last access...
In loop after last access...
答案 1 :(得分:3)
是的,将收集object data
(假设processData()
没有将其放入列表中)。
GC可以处理(托管)线程,如果不能,世界将会结束。
但是你的代码是不线程安全,你的DeQueueing放弃锁定后。
改善建议:
//untested
private bool _forceStop = false;
private object _locker = new object(); // better not depend on queue here
private void ProcessInBackground()
{
while(true)
{
// Moniter.Enter(queue);
lock(_locker)
{
while(!_forceStop && queue.Count == 0)
Moniter.Wait(_locker);
//Moniter.Exit(queue);
if (_forceStop) break;
object data = queue.Dequeue();
}
processData(data);
}
}
编辑:
第二次阅读时,这是关于包含对象的。这当然不受线程的收集。
答案 2 :(得分:1)
假设“对象”是指拥有该方法的实例,那么如果一个线程正在执行ProcessInBackground方法,那么该实例将以该线程为根(它是arg0,并且您正在使用它中的字段环)。所以不,它不会被收集。
如果“对象”是指“数据”,那么除了最近的所有对象都肯定符合条件。最新的可能取决于编译器配置(它是否消除了本地?)和CLI(它是否检查未读取的本地?)。我会说“它可能符合条件,在发布/优化;可能不在调试/未优化”。
答案 3 :(得分:1)
和_forceStop永远不会设置为true,是否会收集对象?
没有
当一个对象的某个方法位于线程的callstack上时,不能对其进行垃圾回收。 callstack有对象的引用。
在这种情况下,ProcessInBackground
是线程的callstack上的方法。
Jon的回答纠正了我的回答 - 当垃圾收集器确信不再使用引用时,包括this
引用。这意味着可以在callstack上有一个方法时收集一个对象(这个方法可能正在使用其他方法,但不使用任何这个实例自己的成员)。
在我自己的代码中,我没有终结器。我收集的东西很少。当我希望收集它们时,它们就不会在那个时候出现在callstack上。如果他们在callstack上被收集,因为.net认为这是件好事,我没问题。
我认为细节不会改变我应该编写任何代码的方式,所以我会选择继续编写代码,好像我上面的错误事实是真的,同时稍微注意它的错误。如果我的情况与您的相似,您也可以这样做。