使用AppDomain.CurrentDomain.AssemblyResolve时内存不足
本文关键字:内存不足 AssemblyResolve CurrentDomain AppDomain 使用 | 更新日期: 2023-09-27 18:25:27
下面的代码有一个内存泄漏。
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?
是的,该事件将导致内存泄漏。这是因为AppDomain.CurrentDomain.AssemblyResolve是静态的,所以在程序结束之前,它的生命不会结束。因此,它必须保留对已向其注册(+=)的所有事件处理程序的引用,以便在事件发生时将其保留在内存中,从而导致调用处理程序。
我建议您在AssemblyResolveMemoryTest类中实现IDisposable,并将其获取到-=事件。
然后在for循环中,添加一个using语句,该语句将导致调用dispose。
for (int i = 0; i < 10; i++)
{
using( AssemblyResolveMemoryTest assemblyResolveMemoryTest = new AssemblyResolveMemoryTest() )
{
}
}
您可以将assemblyResolveMemoryTest实例存储在列表中,并编写第二个循环,在程序存在之前对它们调用Dispose。但这并没有多大意义,因为当你的程序存在时,所有东西都会被处理掉,"泄露的内存"也会被释放。
因此,在现实中,如果你确实希望这些事件处理程序在你的程序生命周期中保持并使用,那么这实际上不是内存泄漏,而是你的程序需要按照你想要的方式运行的内存使用。
我想缓冲区不是真正程序中的东西,你只是在用它来演示问题。也许,如果您在生产代码中有一个真正的assemblyResolveMemoryTest等效对象引用的内存,您可以尝试重组程序,使AssemblyResolve的事件处理程序不属于保存与事件处理无关的其他内存的对象。
您可以使用静态方法作为事件处理程序,这样类的成员对象就不会留在内存中,因为您根本不需要创建类的实例。