问题
I've got an app which creates several AppDomains in a single process and communicates between them via remoting. I create sponsors for all objects to prevent them from being GCed.
But, some ended up being GCed anyway. After some investigation I've determined that depending on the InitialLeaseTime
set on my remote objects, my sponsors are either never called or get called a couple times and then never again.
My sponsor (I've removed some sanity checking for brevity):
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;
}
}
}
My test case:
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;
}
}
If I leave the InitialLeaseTime
at 5 minutes, the .NET default, my sponsor will never be called. If I set it to 2 minutes, it will be called twice and then never again. If I set it to 1 minute, it will be called continually and work how I expected the default values to work.
Update
I've since determined that the ILease
objects of my sponsors themselves are being GCed. They start out with the default 5min lease time, which explains how often my sponsors are being called. When I set my InitialLeaseTime
to 1min, the ILease
objects are continually renewed due to their RenewOnCallTime
being the default of 2min.
What am I doing wrong? I don't see a way to create sponsors for the lease objects of my sponsors.
回答1:
It's been a long time since this question was asked, but I ran into this today and after a couple hours, I figured it out. The 5 minutes issue is because your Sponsor which has to inherit from MarshalByRefObject also has an associated lease. It's created in your Client domain and your Host domain has a proxy to the reference in your Client domain. This expires after the default 5 minutes unless you override the InitializeLifetimeService() method in your Sponsor class or this sponsor has its own sponsor keeping it from expiring.
Funnily enough, I overcame this by returning Null in the sponsor's InitializeLifetimeService() override to give it an infinite timespan lease, and I created my ISponsor implementation to remove that in a Host MBRO.
回答2:
I posted a very similar problem and answer "Sponsor's Renewal function stops being called". It might even be the same problem.
I've worked around it by putting the sponsor on the server instead of the client. The server side sponsor seems to be reliably called enough to keep the remote object alive. I know this won't be a very safe solution in many cases because the client must actively disconnect the sponsor instead of just letting the lease expire.
来源:https://stackoverflow.com/questions/18680664/remoting-sponsor-stops-being-called