我有一个应用程序,它在一个进程中创建多个 AppDomains,并通过远程处理在它们之间进行通信。我为所有对象创建赞助商,以防止它们被 GCed。
但是,无论如何,有些人最终还是被 GCed 了。经过一番调查,我确定根据InitialLeaseTime
我的远程对象上的设置,我的赞助商要么永远不会被调用,要么会被调用几次,然后再也不被调用。
我的赞助商(为简洁起见,我删除了一些健全性检查):
class Sponsor : MarshalByRefObject, ISponsor, IDisposable
{
ILease lease;
public Sponsor(MarshalByRefObject mbro)
{
lease = (ILease)RemotingServices.GetLifetimeService(mbro);
lease.Register(this);
}
public TimeSpan Renewal(ILease lease)
{
return this.lease != null ? lease.InitialLeaseTime : TimeSpan.Zero;
}
public void Dispose()
{
if(lease != null)
{
lease.Unregister(this);
lease = null;
}
}
}
我的测试用例:
class Program : MarshalByRefObject
{
static void Main(string[] args)
{
AppDomain ad = AppDomain.CreateDomain("Remote");
Program obj = (Program)ad.CreateInstanceAndUnwrap(
typeof(Program).Assembly.FullName,
typeof(Program).FullName);
using (new Sponsor(obj))
{
// sleep for 6 minutes.
// 5 seems to be the point where it gets GCed.
Thread.Sleep(6 * 60 * 1000);
// throws a RemotingException
obj.Ping();
}
}
void Ping()
{
}
public override object InitializeLifetimeService()
{
ILease lease = (ILease)base.InitializeLifetimeService();
if (lease.CurrentState == LeaseState.Initial)
{
// this is the .NET default. if used, the lease is never renewed.
//lease.InitialLeaseTime = TimeSpan.FromMinutes(5);
// if uncommented, lease is renewed twice and never again.
//lease.InitialLeaseTime = TimeSpan.FromMinutes(2);
// if uncommented, lease is renewed continually.
//lease.InitialLeaseTime = TimeSpan.FromMinutes(1);
}
return lease;
}
}
如果我离开InitialLeaseTime
5 分钟,.NET 默认值,我的赞助商将永远不会被调用。如果我将其设置为 2 分钟,它将被调用两次,然后再也不会调用。如果我将它设置为 1 分钟,它将被连续调用并按照我期望的默认值工作。
更新
从那以后,我确定ILease
我的赞助商自己的对象正在被 GCed。他们从默认的 5 分钟租赁时间开始,这解释了我的赞助商被呼叫的频率。当我将 my 设置InitialLeaseTime
为 1 分钟时,ILease
对象会不断更新,因为它们RenewOnCallTime
的默认值为 2 分钟。
我究竟做错了什么?我看不到为我的赞助商的租赁对象创建赞助商的方法。