Функция обновления спонсора перестает вызываться
У меня есть сервер и клиентский процесс, работающий на одной машине. Клиент создает объект CAO и использует его в течение некоторого времени (<от 1 до часов). Это занимает много памяти, поэтому я хочу избавиться от этого объекта как можно скорее после того, как клиент закончит с ним.
Я установил InitialLeaseTime и RenewOnCallTime на 10 с (0,1 с и 15 с имеют ту же проблему). Я вижу, что в течение нескольких минут функция спонсора Renweal вызывается каждые 10 секунд. Через несколько минут клиент начинает выполнять другую работу, и спонсор перестает звонить (это кажется неправильным). Через несколько минут, когда клиент пытается использовать удаленный объект, он генерирует исключение, сообщающее, что он был отключен (возможно, потому, что спонсор не вызывался в течение длительного времени).
Кажется, что менеджер по аренде как-то перестает пытаться проверить аренду через некоторое время.
2 ответа
Долгое время между ответами, но я думаю, что другие могут столкнуться с этой проблемой, так что здесь идет.
Я бы порекомендовал подключиться к вашему серверу в 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
- если у вас их два или более, возможно, это событие вызвано переключением между ними), которое, по-видимому, приводит к прекращению чтения сокета. Это означало, что в следующий раз, когда Lease Manager использовал удаленное подключение для проверки удаленной аренды, он не мог прочитать эту аренду из мертвого сокета. Таким образом, он сделал разумную вещь - отключил этого спонсора, так как мы больше не можем его читать, и удалил его из списка спонсоров для объекта. И, поскольку он, вероятно, является единственным спонсором рассматриваемого объекта, этот объект не получает спонсорства от Lease Manger, что дает GC возможность в конечном итоге забрать его.
Один из подходов к решению этой проблемы заключается в InitializeLifetimeService()
метод, вернуть ноль вместо установки времени ожидания. Это обходит LeaseManager, поэтому вам никогда не придется беспокоиться о том, что объект не будет спонсироваться из-за исключения сокета, так как вы в первую очередь не используете аренду. Однако, если вы похожи на меня, это также означает, что вы могли бы накапливать объекты и неуправляемые ресурсы в течение определенного периода времени на сервере. Единственный способ обойти проблему с наращиванием, которую я вижу, это заставить ваш удаленный объект реализовать Dispose
и убедившись, что вы утилизируете его, когда закончите с ним. В принципе, вы не можете полагаться на LeaseManager, обрабатывающий сборку мусора, поэтому вам придется делать GC самостоятельно, по старинке.
Также стоит отметить: объект ITrackingHandler позволит вам отслеживать, когда связанные с Lease Manager объекты отключены, маршалированы и не маршалированы. Это очень помогло выяснить, что происходит, так как я мог видеть, что объект отключался, а не выводить его из-за того, что вызовы перестали происходить.
Я решил эту проблему, разместив спонсора на сервере, а не на клиенте. Спонсор серверной стороны, кажется, достаточно надежно вызван, чтобы поддерживать удаленный объект в живых.
Class SelfSponsor
Implements ISponsor
Public Function Renewal(ByVal lease As ILease) As System.TimeSpan Implements ISponsor.Renewal
Return lease.RenewOnCallTime
End Function
End Class
А в классе удаленного объекта MarshalByRef:
Private Sponsor As SelfSponsor
Public Sub SponsorYourself()
Sponsor = New SelfSponsor
DirectCast(GetLifetimeService(), ILease).Register(Sponsor)
End Sub
Public Sub UnSponsorYourself()
DirectCast(GetLifetimeService(), ILease).Unregister(Sponsor)
End Sub
Каким-то образом код SponsorYourself() генерирует исключение, если он помещен в конструктор, поэтому клиент вызывает SponsorYourself сразу после создания объекта.
Это было бы плохим решением, если сервер всегда работает, а клиенты приходят и уходят, потому что, если клиент выходит ненормально без явного вызова UnsponsorYourself(), тогда объект останется живым навсегда. Но в моем случае сервер запускается и останавливается клиентом, так что это не имеет значения.