.NET事件导致无法控制的内存使用

sta*_*ked 2 .net

假设我们有一个Windows窗体,其中有一个名为SimpleButton1的按钮.以下代码导致无法控制的内存使用量.我做错了什么?

我的理解是,在for循环的每次迭代中,GC都会清理任何TestClass对象,并且会处理任何相关事件,因为任何事件都没有处理程序

Public Class Form1

Private Sub SimpleButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SimpleButton1.Click
    For i = 1 To 1000000
        Dim test1 As New TestClass            
    Next
End Sub
End Class

Public Class TestClass
    Private Event TestEvent(ByVal sender As Object)
End Class
Run Code Online (Sandbox Code Playgroud)

请注意,我已经尝试实现IDisposable并在For循环的每次迭代结束时调用test1.Dispose(),但我怀疑我没有处置正确的资源.

*答案:代码中没有问题,它按预期运行.问题是我在调试模式下运行它,并且创建的开销导致大量内存使用.见下面的讨论.

Jam*_*der 5

你在这里没有展示的,我怀疑的问题是,在你的TestClass中,你有事件TestEvent,而你可能正在向TestEvent添加处理程序,你可能不会删除它们.通过不删除它们,您告诉GC不要收集TestClass或处理程序的类.

  • James,TestEvent的处理程序是TestClass的__outgoing__引用,不会阻止GC.除非实例互相订阅. (2认同)

Bri*_*sio 5

正如您所示,此代码不会泄漏.垃圾收集器最终会处理您创建的类.

但是,如果你有一个Observable类和一个Observer类,Observer将调用Observable.Event += Observer.EventHandler; 通过这样做,Observable现在有一个返回Observer的引用.如果你不打电话Observable.Event -= Observer.EventHandler,那么这个参考就会存在.

当您认为没有人对Observer有引用时会出现问题,但Observable的生命周期更长.尽管Observable具有对Observer的引用,但是除非它清除所有处理程序(this.Event = null),否则没有代码知道删除引用.

实际上,这是一个内存泄漏!

有几种方法可以解决这个问题:

  1. 在抛出Observer之前调用 - =.可能在Dispose()
  2. 使用弱事件
  3. 考虑不同的事件模式,如Event Aggregator