服务的内存泄漏传递给卸载的AppDomain

时间:2014-06-14 17:47:00

标签: c# .net memory-leaks appdomain

我在AppDomains的上下文中遇到内存泄漏。我已将其剥离到以下内容:

我有3个项目,两个库项目和一个控制台项目:Shared,DynamicallyLoadableRemotingTimeoutPrototype(控制台程序)。共享包含DynamicallyLoadableRemotingTimeoutPrototype使用的接口。两者都在编译时引用Shared。任何项目之间都没有其他编译时引用。

共享包含:

public interface IHostService
{
    string GetStuff();
}
public interface IRemoteClass
{
    IHostService Alpha { get; set; }
    string CallHostServices();
}

DynamicallyLoaded只包含一种类型:

public class RemoteClass : MarshalByRefObject, IRemoteClass
{
    public IHostService Alpha { get; set; }
    public string CallHostServices()
    {
        Console.WriteLine("Domain {0}, RemoteClass.CallHostServices():", AppDomain.CurrentDomain.Id);
        return Alpha.GetStuff();
    }
}

控制台项目包含IHostService

的实现
public class Alpha : MarshalByRefObject, IHostService
{
    readonly byte[] mBuffer = new byte[100*1024*1024];
    public Alpha()
    {
        for (var i = 0; i < mBuffer.Length; ++i)
            mBuffer[i] = (byte) (i%256);
    }
    public string GetStuff()
    {
        return "Alpha";
    }
}

Program.Main包括:

while (true)
{
       var otherDomain = AppDomain.CreateDomain("OtherDomain");
       var proxy =
           (IRemoteClass)
            otherDomain.CreateInstanceFromAndUnwrap("../../../DynamicallyLoadable/bin/debug/DynamicallyLoadable.dll",
                        "DynamicallyLoadable.RemoteClass");
       var alpha = new Alpha();
       proxy.Alpha = alpha;
       Console.WriteLine(proxy.CallHostServices());
       Thread.Sleep(TimeSpan.FromSeconds(2));
       AppDomain.Unload(otherDomain);
       RemotingServices.Disconnect(alpha); // this was just an attempt, doesn't change a thing whether it's there or not
       GC.Collect(); // same here, this shouldn't really be necessary, I just tried it out of despair
}

现在,当我让它运行一段时间后,内存消耗不断增加,最终我遇到了OutOfMemoryException。

我希望如果卸载代理的域名,那么代理也会被卸载,并且不再引用具体的Alpha,所以这将被收集。但显然不是。

请注意,我还通过引用mscoree并使用以下代码的代码枚举加载的域来检查域是否真正被卸载:

var runtimeHost = new CorRuntimeHost();
runtimeHost.EnumDomains(out handle);
// etc.

另外,如果我将处理程序附加到otherDomain.DomainUnload(),则可以正常调用此处理程序。

有人可以对此有所了解吗?

1 个答案:

答案 0 :(得分:0)

这可能是阻塞终结线程的典型问题(因为你有while循环,可能是STA线程,并且永远不会明确地控制另一个线程)。即使您卸载/处置域,它也可能在内存中,因为它尚未最终确定。在这里阅读更多内容:http://alexatnet.com/articles/memory-leaks-in-net-applications - 特别是“Blocked Finalization Thread”部分(我是作者)