【问题标题】:MarshalByRefObject becoming "disconnected at server" even while sponsoredMarshalByRefObject 即使在赞助时也会“在服务器上断开连接”
【发布时间】: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 是对象的发起者,只要它保持活动状态,远程域中的对象也将保持活动状态。这就是问题所在,我通过它们的引用访问对象,但我仍然得到“服务器断开连接”异常。这是我的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


【解决方案1】:

使用 .NET 中内置的 ClientSponsor 类。它非常稳定和简单。

这是大多数人在跨 AppDomain 工作时会求助的方法。您的实现看起来不错,但可能就像您的 SponsorTime() 没有从配置中返回正确的值一样简单。

【讨论】:

    【解决方案2】:

    我在this StackOverflow post 中发现了一些似乎更简单的解决方案。

    它包括告诉对象具有无限的生命周期,这样做:

    [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
    public override object InitializeLifetimeService()
    {
      return null;
    }
    

    这个解决方案不是一致的,但该帖子为我们带来了更多有价值的答案。

    【讨论】:

      猜你喜欢
      • 2015-06-12
      • 2014-04-13
      • 1970-01-01
      • 2022-08-11
      • 2015-11-29
      • 1970-01-01
      • 2013-05-31
      • 1970-01-01
      • 2014-12-02
      相关资源
      最近更新 更多