Утечка памяти - исключение WCF - PullRequest
3 голосов
/ 23 февраля 2012

Мое приложение ASP.NET MVC3 использует Ninject для создания экземпляров служб через оболочку.Конструктор контроллера имеет параметр IMyService, а методы действия вызывают myService.SomeRoutine ().Доступ к службе (WCF) осуществляется через SSL с помощью wsHttpBinding.

У меня есть процедура поиска, которая может вернуть столько результатов, что она превышает максимум, настроенный в WCF (максимальное количество элементов, которые можно сериализовать илидесериализовано в графе объектов).Когда это происходит, пулы приложений как для службы, так и для клиента заметно растут и остаются раздутыми далеко после окончания запроса.

Я знаю, что могу ограничить количество результатов или использовать DTO для уменьшения суммыпередаваемых данных.Тем не менее, я хочу исправить то, что выглядит как утечка памяти.

Используя CLR Profiler , я вижу, что большая часть кучи используется следующим образом:

  • System.RunTime.
  • System.ServiceModel.Channels.SecurityChannelListener
  • System.ServiceModel.Channels.HttpsChannelListener
  • System.ServiceModel.Channels.Text * MessageEncoderFactMacSecMeviceMactory 1024 * 10.TextMessageEncoderFactory.TextMessageEncoder
  • System.NuntimeSystem.Runtime.SynchronizedPool.GlobalPool
  • System.ServiceModel.Channels.BufferManagerOutputStream
  • Система.Байт [] []
  • System.Byte [] (92%)

Кроме того, если я изменю процедуру поиска, чтобы она возвращала пустой список (в то время как материал NHibernate все еще идетв фоновом режиме - проверяется с помощью ведения журнала), размеры пула приложений остаются неизменными.Если процедура поиска возвращает значимые результаты без исключения, размеры пула приложений остаются неизменными.Я полагаю, что утечка происходит, когда список объектов сериализуется, и приводит к исключению.

Я обновил до новейшего Ninject и использовал log4net, чтобы проверить, что клиент службы был закрыт или прерван в зависимости от его состояния (исостояние никогда не нарушалось).Единственное, что мне показалось интересным, было то, что служебная оболочка была завершена и не была явно удалена.

У меня возникают проблемы с устранением неполадок, чтобы выяснить, почему мои пулы приложений не освобождают память в этом сценарии.Что еще я должен смотреть?

ОБНОВЛЕНИЕ: Вот обязательный ...

<wsHttpBinding>
 <binding name="wsMyBinding" closeTimeout="00:01:00" openTimeout="00:01:00" 
  receiveTimeout="00:02:00" sendTimeout="00:02:00" bypassProxyOnLocal="false" 
  transactionFlow="false" hostNameComparisonMode="StrongWildcard" 
  maxBufferPoolSize="999999" maxReceivedMessageSize="99999999" 
  messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="false" 
  allowCookies="false">
  <readerQuotas maxDepth="90" maxStringContentLength="99999" 
  maxArrayLength="99999999" maxBytesPerRead="99999" 
  maxNameTableCharCount="16384" />
  <reliableSession enabled="false" />
  <security mode="TransportWithMessageCredential">
   <message clientCredentialType="UserName" />
  </security>
 </binding>
</wsHttpBinding>

ОБНОВЛЕНИЕ # 2 : ВотНепрямое связывание, но более любопытным является сообщение об ошибке.Моя оболочка неправильно настроила MaxItemsInObjectGraph, поэтому использовала значение по умолчанию.Как только я установил это, утечка ушла.Похоже, что клиент и служба хранят сериализованные / десериализованные данные в памяти, когда служба отправляет сериализованные данные клиенту, а клиент отклоняет их, поскольку они превышают MaxItemsInObjectGraph.

Ninject Binding:

Bind<IMyService>().ToMethod(x => 
    new ServiceWrapper<IMyService>("MyServiceEndpoint")
    .Channel).InRequestScope();

Сообщение об ошибке:

Сообщение InnerException было «Максимальное количество элементов, которые можно сериализовать или десериализовать в графе объектов, равно« 65536 '

Это на самом деле не устраняет утечку памяти, поэтому мне все еще интересно, что вызвало ее, если у кого-то есть идеи.

1 Ответ

1 голос
/ 24 февраля 2012

Как вы справляетесь с созданием и удалением вашего прокси-клиента?

Я обнаружил, что наиболее частой причиной утечек памяти, связанных с WCF, является неправильная обработка прокси-клиентов WCF.

Я предлагаю, по крайней мере, обернуть ваших клиентов блоком using вроде этого:

using (var client = new WhateverProxyClient())
{
  // your code goes here
}

Это обеспечивает правильное закрытие и удаление клиента, освобождая память.

Хотя этот метод немного спорный, но он должен устранить возможность утечки памяти при создании клиента.

Посмотрите здесь , чтобы узнать больше по этой теме.

...