假设我们有一个带有名为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(),但我怀疑我没有处理正确的资源。
*已回答:代码中没有问题,它按预期运行。问题是我在调试模式下运行它,并且创建的开销导致大量内存使用。见下面的讨论。
答案 0 :(得分:5)
你没有在这里展示我怀疑的问题是,在你的TestClass中,你有事件TestEvent,而你可能正在向TestEvent添加处理程序,你可能不会删除它们。通过不删除它们,您告诉GC不要收集TestClass或处理程序的类。
答案 1 :(得分:5)
如您所示,此代码不会泄漏。垃圾收集器最终将处理您创建的类。
但是,如果你有一个Observable类和一个Observer类,Observer将调用Observable.Event += Observer.EventHandler;
通过这样做,Observable现在有一个返回Observer的引用。如果你没有打电话给Observable.Event -= Observer.EventHandler
,那么这个参考就会一直存在。
当您认为没有人对Observer有引用时会出现问题,但Observable的生命周期更长。尽管Observable具有对Observer的引用,但是没有代码可以知道删除引用,除非它清除所有处理程序(this.Event = null
)。
这实际上是内存泄漏!
有几种方法可以解决这个问题:
答案 2 :(得分:3)
GC不会在每次迭代时开始动作,它会等到一个合适的时刻并整体扫除这些对象。
TestEvent不应阻止GC的收集,但如果TestClass的实例在另一个对象上订阅一个事件,那么这将使它们保持活动状态。没有自动清理。
如何确定“导致无法控制的内存使用量”。测量内存使用量比听起来更难。我希望这不是基于TaskManager。
答案 3 :(得分:3)
如果您在Debug下运行,VisualStudio将创建额外的代码来帮助编辑和继续(_EncList stuff),即使您不在调试器下。
确保编译并在编译为“发布”的生产中运行。是的,这使得当它们的行为不同时很难调试内存问题,但这并不是追踪内存问题最困难的事情。