【发布时间】:2012-03-03 01:00:20
【问题描述】:
(抱歉,如果以前出现过这种情况,我已经搜索但没有找到任何与我的搜索词相关的内容)
鉴于以下情况:
void Method1 {
Foo _foo = new Foo();
_foo.DataReady += ProcessData();
_foo.StartProcessingData();
}
void ProcessData() { //do something }
StartProcessingData() 是一个长时间运行的方法,最终(异步)引发DataReady 事件。 (假设它进行了服务调用或其他操作)
现在,_foo 曾经是一个类级别的变量,而事件过去是在构造函数中连接起来的。
但是,内存分析强调了这将如何将 _foo 及其所有依赖项永远保留在内存中,因此我对上述内容进行了更改。
我的问题是:有没有 GC 会毁掉一切的情况? Method1 很快结束(当然在事件触发之前),这意味着_foo 不再存在。但是,这是否意味着(因为 _foo 保留其事件的引用)ProcessData() 永远不会触发?或者,事件的存在是否足以让 _foo 在方法结束后保持活动状态,足以确保 ProcessData 触发?还是没有定论?
[在测试中,它运行良好——ProcessData 总是被调用。即使让StartProcessingData 花费很长时间,并且在中途强制GC 收集(使用RedGate 的Memory Profiler)也没有删除它。但我想确定!]
澄清:StartProcessingData() 立即返回。 Foo 对象类似于:
class Foo
{
SomeSerice _service;
event EventHandler<EventArgs> DataReady;
Foo()
{
_service = new SomeService();
_service.ServiceCallCompleted += _service_ServiceCallCompleted;
}
void StartProcessingData()
{
_service.ServiceCallAsync();
}
void _service_ServiceCallCompleted
{
DataReady(null,e);
}
所以,抽象和模拟一个长期运行的异步服务,使用事件来表示重要的,呃,事件。
这是一个完整的工作示例(控制台应用)
class Program
{
static void Main(string[] args)
{
Class1 _class1 = new Class1();
Console.WriteLine("Disposing of Class 1");
_class1 = null;
GC.Collect();
System.Threading.Thread.Sleep(15000);
Console.Read();
}
}
internal class Class1
{
internal Class1()
{
Foo _foo = new Foo();
_foo.DataReady += new EventHandler<EventArgs>(_foo_DataReady);
_foo.StartProcessingData();
}
void _foo_DataReady(object sender, EventArgs e)
{
Console.WriteLine("Class 1 Processing Data");
}
}
class Foo
{
internal event EventHandler<EventArgs> DataReady = delegate { };
internal void StartProcessingData()
{
System.Threading.Timer _timer = new System.Threading.Timer(OnTimer);
Console.WriteLine("Firing event in 10 secs");
_timer.Change(10000, System.Threading.Timeout.Infinite);
}
private void OnTimer(object state)
{
DataReady(this, null);
}
}
如果你运行它,你会得到:
Firing event in 10 secs
Disposing of Class 1
Class 1 Processing Data
【问题讨论】:
-
StartProcessingData 是静态的是不是错字?或者你的意思是把 _foo.StartProcessingData()
-
是的,这是一个错字。现在修复:谢谢:)
-
我不确定我是否完全关注你。我假设
StartProcessingData实际上会调用处理程序。如果是这种情况,那么Method1在此调用完成之前不会完成,就像现在的代码一样。 -
抱歉,我没有明确说明 StartProcessingData 会异步引发事件。我将编辑原件。
标签: c# .net garbage-collection