使用AppDomain.CurrentDomain.AssemblyResolve时Memoryleak

时间:2012-02-23 09:06:31

标签: c# memory-leaks

以下代码有记忆漏洞。

class Program
{
    static void Main(string[] args)
    {
        for (int i = 0; i < 10; i++)
        {
            AssemblyResolveMemoryTest assemblyResolveMemoryTest = new AssemblyResolveMemoryTest();
        }
    }
}

class AssemblyResolveMemoryTest 
{
    private byte[] _allocateMemory;

    public AssemblyResolveMemoryTest()
    {
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
        //memory is not released anymore
        _allocateMemory = new byte[300000000]; 
    }
    System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        return null;
    }
}

似乎AssemblyResolve事件导致内存泄漏。

这是什么原因? 在这种情况下,我是否需要显式删除事件处理程序? 如果是,删除此事件处理程序的正确位置在哪里?实现IDisposable或使用Try / Finally?

1 个答案:

答案 0 :(得分:3)

是的,该事件将导致内存泄漏。这是因为AppDomain.CurrentDomain.AssemblyResolve是静态的,所以它的生命不会在程序结束之前结束。因此,它必须保留对已注册(+ =)的所有事件处理程序的引用,以便它们在事件发生时保留在内存中,这将导致处理程序被调用。

我建议您在AssemblyResolveMemoryTest类中实现IDisposable并将其转换为 - =事件。

然后在for循环中添加一个using语句,该语句将导致调用dispose。

    for (int i = 0; i < 10; i++)
    {
        using( AssemblyResolveMemoryTest assemblyResolveMemoryTest = new AssemblyResolveMemoryTest() )
        {
        }
    }

您可以将assemblyResolveMemoryTest实例存储在列表中,并编写第二个循环,在程序存在之前调用Dispose。这里没有多大意义,因为当你的程序存在时,一切都将被处置,并且“泄露的记忆”将被释放。

所以,实际上,如果你确实希望这些事件处理程序保留并在程序的生命周期中使用,那么这实际上不是内存泄漏,而是程序需要的内存使用情况,因为你想要它到。

我想缓冲区不是你在真实程序中的东西,而你只是用它来演示问题。也许,如果您的生产代码中有一个真正的assemblyResolveMemoryTest等效对象引用了内存,您可以尝试重构您的程序,以便AssemblyResolve的事件处理程序不是保留到与其他内存无关的对象的一部分。处理事件。

您可以使用静态方法作为事件处理程序,这样该类的任何成员对象都不会留在内存中,因为您实际上不需要首先创建该类的实例。