代码之家  ›  专栏  ›  技术社区  ›  stacked

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

  •  2
  • stacked  · 技术社区  · 15 年前

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

    我的理解是,在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
    

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

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

    4 回复  |  直到 15 年前
        1
  •  3
  •   Philip Rieck    15 年前

    如果您在调试下运行,即使您不在调试程序下,VisualStudio也将创建额外的代码来帮助您编辑并继续(ou enclist stuff)。

    确保编译并在编译为“release”的产品中运行。是的,这使得在内存问题的行为不同时很难调试它们,但是跟踪内存问题并不是最困难的事情。

        2
  •  5
  •   James Alexander    15 年前

    这里您没有显示的问题是,在您的testClass中,您有事件testevent,虽然您可能正在向testevent添加处理程序,但您可能没有删除它们。不删除它们,就是告诉GC不要收集testclass或处理程序的类。

        3
  •  5
  •   Brian Genisio    15 年前

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

    但是,如果您有一个可观察类和一个观察类,那么观察类将调用 Observable.Event += Observer.EventHandler; 通过这样做,可观测到的现在有了一个回到观察者的参考。如果你不打电话 Observable.Event -= Observer.EventHandler ,然后那个引用就在附近。

    当你认为没有人提到观察者,但观察者的寿命更长时,就会出现这种情况。虽然observable有一个对观察者的引用,但是没有代码知道删除引用,除非它清除了所有的处理程序。( this.Event = null )

    实际上,这是内存泄漏!

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

    1. 在你把观察者赶出去之前打电话-。可能在Dispose()中
    2. 使用 Weak Events
    3. 考虑一个不同的事件模式,比如 Event Aggregator
        4
  •  3
  •   Henk Holterman    15 年前
    1. GC不会在每次迭代中都启动,它将等到一个合适的时刻,然后一起清理这些对象。

    2. TestEvent不应该阻止GC的收集,但是如果TestClass的实例订阅了另一个对象上的事件,那么它将使它们保持活动状态。没有自动清理。

    3. 如何确定“导致无法控制的内存使用量”。测量内存使用比听起来更困难。我希望这不是基于任务管理器。