【发布时间】:2014-03-24 18:16:18
【问题描述】:
我正在编写一个支持模组的游戏,为了安全起见,我将模组沙盒化到与游戏引擎分开的 AppDomain 中(因此我可以将模组的功能与引擎分开限制)。但是,引擎保留引用的脚本域中的对象会过早地收集垃圾,我得到这样的异常:
对象 '/30b08873_4929_48a5_989c_e8e5cebc601f/lhejbssq8d8qsgvuulhbkqbo_615.rem' 已断开连接或在服务器上不存在。
在服务器端,我正在创建这样的对象(使用 AppDomainToolkit:
// Take in a "script reference" which is basically just the name of a type in the scripting domain
public Reference<T> Dereference<T>(ScriptReference reference) where T : MarshalByRefObject
{
// Create a remote instance of this type
T instance = (T)RemoteFunc.Invoke<ScriptReference, object>(_pluginContext.Domain, reference, r =>
{
var t = Type.GetType(r.TypeName, true, false);
return Activator.CreateInstance(t);
});
//Return a reference which keeps this object alive until disposed
return new Reference<T>(instance, reference.TypeName, reference.Name);
}
这个想法是 Reference
public sealed class Reference<T>
: IDisposable
where T : MarshalByRefObject
{
private InnerSponsor _sponsor;
public T RemoteObject
{
get { return _sponsor.RemoteObject; }
}
public string TypeName { get; private set; }
public string Name { get; private set; }
public Reference(T obj, string typeName = null, string name = null)
{
TypeName = typeName;
Name = name;
_sponsor = new InnerSponsor(obj);
}
~Reference()
{
if (_sponsor != null)
_sponsor.Dispose();
_sponsor = null;
}
public void Dispose()
{
_sponsor.Dispose();
GC.SuppressFinalize(this);
}
/// <summary>
/// Inner sponsor is the actual sponsor (and is kept alive by the remoting system).
/// If all references to Reference are lost, it will dispose the sponsor in its destructor
/// </summary>
private sealed class InnerSponsor
: MarshalByRefObject, ISponsor, IDisposable
{
private readonly ILease _lease;
private bool _isDisposed;
public readonly T RemoteObject;
private bool _isUnregistered = false;
public InnerSponsor(T obj)
{
RemoteObject = obj;
_lease = (ILease)obj.GetLifetimeService();
_lease.Register(this, SponsorTime());
}
public TimeSpan Renewal(ILease lease)
{
if (lease == null)
throw new ArgumentNullException("lease");
if (_isDisposed)
{
if (!_isUnregistered)
{
_lease.Unregister(this);
_isUnregistered = true;
}
return TimeSpan.Zero;
}
return SponsorTime();
}
private static TimeSpan SponsorTime()
{
return TimeSpan.FromMilliseconds(/*Some value fetched from configuration*/);
}
public void Dispose()
{
_isDisposed = true;
}
}
}
我做错了什么导致我的对象死亡,即使它们有一个实时的Reference
【问题讨论】:
-
有什么原因,你不使用内置的
ClientSponsor?如果没有调用InitializeLifetimeService(),也可能是您的 AppDomain 正在死去,这将开始对您的实例造成严重破坏。 -
只是因为我不知道 ClientSponsor 的存在!我假设 AppDomainToolkit 为我处理调用 InitializeLifetimeService,我会检查一下。
-
实际上,我知道 AppDomain 绝对不会死,因为一些远程对象仍然可以正常工作,而另一些则断开连接。
-
我会尝试使用它然后进行测试,因为它应该很容易实现并且是大多数人使用的;包括我自己。
-
到目前为止,使用 ClientSponsor 似乎有效。显然,考虑到问题的性质和 GC 在它想要的时候做它想做的事情,这有点难说!
标签: c# debugging .net-remoting