C# 使用AppDomain.CurrentDomain.AssemblyResolve时的Memoryleak

C# 使用AppDomain.CurrentDomain.AssemblyResolve时的Memoryleak,c#,memory-leaks,C#,Memory Leaks,下面的代码有一个memoryleak class Program { static void Main(string[] args) { for (int i = 0; i < 10; i++) { AssemblyResolveMemoryTest assemblyResolveMemoryTest = new AssemblyResolveMemoryTest(); } } } class

下面的代码有一个memoryleak

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;
    }
}
类程序
{
静态void Main(字符串[]参数)
{
对于(int i=0;i<10;i++)
{
AssemblyResolveMemoryTest AssemblyResolveMemoryTest=新的AssemblyResolveMemoryTest();
}
}
}
类AssemblyResolveMemoryTest
{
专用字节[]分配内存;
公共程序集ResolveMemoryTest()
{
AppDomain.CurrentDomain.AssemblyResolve+=CurrentDomain_AssemblyResolve;
//内存不再被释放
_allocateMemory=新字节[300000000];
}
System.Reflection.Assembly CurrentDomain_AssemblyResolve(对象发送方,ResolveEventArgs args args)
{
返回null;
}
}
AssemblyResolve事件似乎导致内存泄漏

这是什么原因? 在这种情况下,是否需要显式删除eventhandler?
如果是,删除此eventhandler的正确位置在哪里?实现IDisposable还是使用Try/Finally

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

我建议您在AssemblyResolveMemoryTest类中实现IDisposable,并将其发送到-=事件

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

    for (int i = 0; i < 10; i++)
    {
        using( AssemblyResolveMemoryTest assemblyResolveMemoryTest = new AssemblyResolveMemoryTest() )
        {
        }
    }
for(int i=0;i<10;i++)
{
使用(AssemblyResolveMemoryTest AssemblyResolveMemoryTest=new AssemblyResolveMemoryTest())
{
}
}
您可以将assemblyResolveMemoryTest实例存储在一个列表中,并在程序存在之前编写第二个循环,循环调用Dispose。但这并没有多大意义,因为当你的程序存在时,所有的东西都会被处理掉,“泄漏的内存”会被释放

因此,在现实中,如果您确实希望这些事件处理程序在您的程序生命周期内保持并使用,那么这实际上不是内存泄漏,而是您的程序需要的内存使用量,以使其按您的意愿运行

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


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

在经常打开/关闭的带有elementhost/xaml的winform上使用此memoryleak时,我们已经在生产中使用了它。这会导致每次泄漏约10mb。但是我会使用一个静态事件处理程序。你需要重新考虑三百兆字节的数组。这只是为了显示效果。即使我只向数组中添加一个字节,内存泄漏仍然会存在。