此问题基于以下问题: How to dispose the local variable that contains event
有人说:一个实例的一个事件处理程序,实例的引用计数会被添加吗?为什么呢?
答案 0 :(得分:2)
正如Jon Skeet所说,你的相关问题已经倒退了。保持watcher
活着的唯一事情可能是它自己的内部实现,它可能(或可能不)用较低级别的对象注册事件,该对象负责反馈" ticks"。 - 这只是猜想。
点击该按钮两次将产生两个单独的 watcher
个实例,每个实例都有一个订阅者PositionChanged
事件(恰好是在同一个实例上使用相同的方法。)
重要的是,并非 PositionChanged
订阅者在方法退出后保持watcher
活着 - 这是其他内容(我怀疑是在{ {1}}实施)。当方法退出时,对GeoCoordinateWatcher
的特定实例的引用正确从堆栈中弹出,但由于另一个引用保留在{{1}上CLR眼中的有效引用计数仍然大于零 - 因此, 不 符合垃圾回收的条件。
因此,它将继续发起watcher
事件。由于事件中没有任何内容阻止观察者继续,我猜你可能会有内存泄漏,因为每次点击按钮都会创建并且保持活着一个观察者实例。
您需要存储和使用一个watcher
类,或者每次处理事件时关闭/处置/停止它。
<小时/> 对事件和订阅的通常考虑是注意订阅长期对象的短期对象。
委托持有对类的特定实例中的特定方法的引用(如果它是静态方法,则仅包含类型本身)。订阅事件会导致事件发布者无意中通过订阅代理持有对订阅者实例的引用。
显然,如果将静态方法注册为事件处理程序,则由于没有实例,因此无法获得此引用计数。
如果订阅者是短暂的并且事件发布者是长期存在的,如果您没有取消订阅,则可能发生内存泄漏。假设订阅者希望有资格获得GC,因为它对某个地方的某个事件进行了有效订阅,并且该对象仍然存在,在从该订阅列表中删除之前,它不能符合条件。
答案 1 :(得分:0)
通过调用GeoCoordinateWatcher.Start启动新的任务。即使它在您的代码中声明为local
变量,它也会在退出函数范围后继续生效。
你可以考虑这个,就像你从函数中开始第三部分process
一样。功能的范围消失了,但过程仍然存在。
在提供的链接中,如果您单击两次按钮,则会导致{strong>相同事件处理程序处理GeoCoordinateWatcher
的2个不同实例。因此,事件处理程序将从GeoCoordinateWatcher
的两个不同实例中调用两次。
答案 2 :(得分:0)
创建委托对象时,它包含Method
和Target
属性。 Target属性指向将在其中调用Target
方法的上下文的对象(第一个参数,即this
)。
在某些情况下,对委托对象的引用将处于活动状态,从而阻止Target
实例被GCed。它通常发生在你有一个基于插件/插件的应用程序,或者某种其他类型的后期绑定情况,或者你在委托中做了很多工作并且委托对象存储在某个集合中,或者你有一个静态字段使用委托对象,(因为永远不会收集静态字段)等。
请记住,垃圾收集不容易受到“循环引用”问题的影响;对于一个被认为“有用”的对象,它必须可以从当前堆栈中访问。