以下代码有记忆漏洞。
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?
答案 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的事件处理程序不是保留到与其他内存无关的对象的一部分。处理事件。
您可以使用静态方法作为事件处理程序,这样该类的任何成员对象都不会留在内存中,因为您实际上不需要首先创建该类的实例。