很长一段时间的回应,但我认为其他人也可能遇到这个问题,所以就这样吧。
我建议在 VS 中附加到您的服务器,转到“调试”菜单,选择“异常”,然后检查“System.Net.Sockets.SocketException”异常。这将在发生任何套接字异常时中断您的程序。
就我而言,我最近开始看到这个问题,经过大量调试后发现,就在租赁管理器停止检查租约之前,发生了 SocketException。在我的情况下,套接字异常是AddressChangedCallback
,带有堆栈跟踪:
1 [External Code]
2 System.dll!System.Net.Dns.TryGetAddrInfo(string name = "me.win.mycompany.com", System.Net.AddressInfoHints flags, out System.Net.IPHostEntry hostinfo = null)
3 System.dll!System.Net.Dns.GetAddrInfo(string name)
4 System.dll!System.Net.Dns.InternalGetHostByName(string hostName, bool includeIPv6)
5 System.dll!System.Net.Dns.GetHostEntry(string hostNameOrAddress)
6 System.Runtime.Remoting.dll!System.Runtime.Remoting.Channels.CoreChannel.UpdateCachedIPAddresses()
7 System.Runtime.Remoting.dll!System.Runtime.Remoting.Channels.CoreChannel.OnNetworkAddressChanged(object sender = null, System.EventArgs e = {System.EventArgs})
8 mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
9 mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
10 mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state)
11 System.dll!System.Net.NetworkInformation.NetworkChange.AddressChangeListener.AddressChangedCallback(object stateObject, bool signaled)
12 mscorlib.dll!System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(object state, bool timedOut)
13 [External Code]
在我的情况下,这AddressChangedCallback,
似乎与网络适配器出现故障或被更改有关(您可以通过按住windows+r
然后键入来查看您的网络适配器ncpa.cpl
- 如果您有两个或更多,则此事件可能是由您在它们之间切换引起的)似乎导致套接字停止读取。这意味着下次 LeaseManager 使用远程连接来检查远程租约时,它无法从死套接字中读取该租约。因此,它做了合理的事情——断开该赞助商,因为我们无法再阅读它,并将其从对象的赞助商列表中删除。而且由于它可能是所讨论对象的唯一赞助商,因此该对象随后会被 LeaseManger 取消赞助,从而让 GC 最终获得它。
解决此问题的一种方法是,在您的InitializeLifetimeService()
方法中,返回 null 而不是设置超时。这绕过了 LeaseManager,因此您不必担心对象会因为套接字异常而被取消赞助,因为您一开始就没有使用租约。但是,如果您像我一样,这也意味着您可能会在一段时间内在服务器上积累对象和非托管资源。我能看到的解决构建问题的唯一方法是让你的远程对象实现Dispose
,并确保你在完成后处理它。基本上,您不能依赖 LeaseManager 处理垃圾收集,因此您必须自己进行 GC,这是老式的方式。
另外值得注意的是:ITrackingHandler对象将允许您跟踪与 LeaseManager 相关的对象何时断开连接、编组和取消编组。这对弄清楚发生了什么很有帮助,因为我可以看到一个对象正在断开连接,而不是从调用停止发生的事实中推断出来。