请问因事件处理程序导致.NET中的内存泄漏示例?

Dim*_*ima 5 .net memory events memory-leaks event-handling

在这里和那里,人们一直在谈论由于未发布的事件监听器而发生的内存泄漏.我认为这是一个非常重要的问题.非常严肃而且非常重要......如果确实存在的话.

我曾尝试自己来重现问题,但我所有的努力都失败了:我不能让我的应用程序泄漏内存:(虽然这听起来不错,我还是很担心:也许我失去了一些东西.

那么也许有人可以提供一个非常简单的源代码示例,导致内存泄漏?

我创建了一个小型VB.NET应用程序作为演示:它包含一个Windows窗体和一个类.

Windows窗体:它有一个集合对象(名为"c")和两个按钮:一个用于向集合添加10个项目,另一个用于清除集合:

Public Class Form1

Dim c As New Collection

Private Sub btnAddItem_Click(sender As System.Object, e As System.EventArgs) Handles btnAddItem.Click
    For i As Integer = 1 To 10
        Dim m As New MyType
        c.Add(m)
    Next

    Me.Text = c.Count
End Sub

Private Sub btnClear_Click(sender As System.Object, e As System.EventArgs) Handles btnClear.Click
    For Each item As MyType In c
        item.Dispose()
    Next
    c.Clear()

    Me.Text = c.Count
End Sub
End Class
Run Code Online (Sandbox Code Playgroud)

MyType类:它有很大的m_Image对象,这个对象很大,所以你可以看到你的内存真正被MyType实例占用了:)

Imports System.Drawing

Public Class MyType 
Implements IDisposable

Private m_Image As Bitmap

Public Sub New()
    AddHandler Application.Idle, AddressOf Application_Idle

    m_Image = New Bitmap(1024, 1024)
End Sub

Private Sub Application_Idle(sender As Object, e As EventArgs)

End Sub

#Region "IDisposable Support"
Private disposedValue As Boolean

Protected Overridable Sub Dispose(disposing As Boolean)
    If Not Me.disposedValue Then
        If disposing Then
            m_Image.Dispose()
        End If
    End If
    Me.disposedValue = True
End Sub

Public Sub Dispose() Implements IDisposable.Dispose
    Dispose(True)
    GC.SuppressFinalize(Me)
End Sub
#End Region

End Class
Run Code Online (Sandbox Code Playgroud)

Jar*_*Par 12

这是一个非常直截了当的例子

class MyType
{
    public static event EventHandler ExampleEvent;

    public MyType()
    {
        ExampleEvent += (sender, e) => OnExampleEvent();
    }
    private void OnExampleEvent() { }
}
Run Code Online (Sandbox Code Playgroud)

任何实例MyType将订阅该ExampleEvent事件.此事件未附加到任何特定对象,因此它永远不会留下内存.这将MyType在应用程序的持续时间内保存内存中的所有实例.

编辑

正如在评论中所要求的那样,该MyType实例在不再使用后很长一段时间内停留在内存中

class Program
{
    static void Main(string[] args)
    {
        WeakReference weakRef = new WeakReference(new MyType());
        for (var i = 0; i < 10; i++)
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        Console.WriteLine("Still Alive: {0}", weakRef.IsAlive);
    }
}
Run Code Online (Sandbox Code Playgroud)