使用 AppDomain.CurrentDomain.AssemblyResolve 时出现内存泄漏

发布于 2025-01-08 07:33:54 字数 830 浏览 0 评论 0原文

以下代码存在内存泄漏。

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?

The following code has a 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;
    }
}

It seems the AssemblyResolve event cause the memory leak.

What is the reason for this?
Do i need to remove the eventhandler explicitly in this case?
If yes, where is the right place to remove this eventhandler? Implement IDisposable or use Try/Finally?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

东风软 2025-01-15 07:33:54

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

我建议您在 AssemblyResolveMemoryTest 类中实现 IDisposable 并将其获取到 -= 事件。

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

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

您可以将 assemblyResolveMemoryTest 实例存储在列表中,并编写第二个循环,在程序存在之前对它们调用 Dispose。但这没有多大意义,因为当您的程序存在时,所有内容都将被处置,并且“泄漏的内存”将被释放。

因此,实际上,如果您确实希望这些事件处理程序保留并在程序的整个生命周期中使用,那么这实际上并不是内存泄漏,而是您的程序需要按您希望的方式运行的内存使用情况。

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

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

Yes, the event will cause a memory leak. It's because AppDomain.CurrentDomain.AssemblyResolve is static, so its life doesn't end until the program ends. So, it will have to keep a reference to all event handlers that have been registered (+=) to it so that they remain in memory when an event occurs which will result in the handlers being called.

I would suggest that you implement IDisposable in class AssemblyResolveMemoryTest and get it to -= the event.

Then within the for loop, add a using statement which will cause the dispose to be called.

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

You could store the assemblyResolveMemoryTest instances in a list and write a second loop that goes round calling Dispose on them before your program exists. There's not much point in this though because when your program exists, everything will be dispose and the 'leaked memory' will be freed.

So, in reality, if you do want these event handlers to remain and be in use for the life of your program, then this isn't actually a memory leak and is memory usage your program needs to function as you want it to.

I guess the buffer isn't something you have in a real program, and you're just using it to demonstrate the problem. Perhaps, if you've got memory referenced by your a real assemblyResolveMemoryTest equivalent object in production code, you could try and restructure your program so that the event handler for AssemblyResolve isn't part of an object that holds onto other memory that's not relevant to the handling of the event.

You could use a static method as the event handler, so that no member objects of the class will stay around in memory as you won't actually need to create an instance of the class in the first place.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文