Компактная структура — утечка ресурсов HttpWebRequest в автономном режиме

Итак, это приложение .NET CF 3.5, работающее на CE7. Проблема видна и в CE5.

Мы используем HttpWebRequests для запроса сервера. В онлайне вроде все хорошо.

Когда сервер недоступен, мы наблюдаем то, что выглядит как утечка ресурсов.

Используя удаленный монитор производительности CF, мы можем видеть, как накапливаются (в конце концов) десятки тысяч слабых ссылок, которые никогда не исчезают. Занимает кучу памяти. Куча растет линейно. Смотрите скриншоты.

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

Когда запрос завершен (или возникает исключение), мы удаляем IDisposables в запросе (поток запроса и поток ответа).

Не могли бы вы объяснить, что здесь происходит, пожалуйста? Почему все эти слабые ссылки накапливаются, а не собираются мусором? Любое понимание ценится.

Спасибо.

RMPRMP RMPRMP

РЕДАКТИРОВАТЬ:

Вероятно, также стоит упомянуть, что в отладчике мы иногда видим это исключение ObjectDisposedException, которое не перехвачено и приводит к падению приложения (поскольку оно находится в потоке Threadpool). Только изредка. Может быть/не быть связано с вышеуказанной утечкой. Мы перепробовали все возможные варианты использования/удаления/не удаления/закрытия потоков и все советы по этому поводу, но безрезультатно.

   at System.Threading.Timer.throwIfDisposed()
   at System.Threading.Timer.Change(UInt32 dueTime, UInt32 period)
   at System.Threading.Timer.Change(Int32 dueTime, Int32 period)
   at System.Net.HttpWebRequest.startReadWriteTimer()
   at System.Net.HttpWebRequest.ConnectionClient.Read(Byte[] data, Int32 offset, Int32 length)
   at System.Net.HttpReadStream.NetworkRead(Byte[] data, Int32 offset, Int32 length)
   at System.Net.ContentLengthReadStream.doRead(Byte[] data, Int32 offset, Int32 length)
   at System.Net.HttpReadStream.ReadToDrain(Byte[] buffer, Int32 offset, Int32 length)
   at System.Net.HttpReadStream.doClose()
   at System.Net.ContentLengthReadStream.doClose()
   at System.Net.HttpReadStream.Finalize()

person Nik    schedule 13.06.2014    source источник
comment
Можете ли вы показать пример кода, в котором вы создаете и выпускаете эти слабые ссылки?   -  person brainless coder    schedule 23.06.2014
comment
@Nik - на самом деле невозможно помочь без какой-либо части кода, показывающей, как вы выполняете вызовы HttpWebRequest. Я сомневаюсь, что с HttpWebRequest что-то не так, скорее всего, это просто проблема с тем, как вы его вызываете и обрабатываете исключения в этом случае (особенно с учетом того, что вы накапливаете WebExceptions... Интересно, создаете ли вы новый HttpWebRequest в своем обработчик исключений, что фактически приводит к бесконечной рекурсии и невозможности собирать запросы выше по стеку).   -  person huntharo    schedule 25.06.2014


Ответы (1)


  1. ObjectDisposedException

Согласно MSDN, в Соглашении Рамки

[a] поток запроса с нулевой длиной содержимого вызывает ObjectDisposedException, если он не был получен и закрыт правильно. Для обработки запросов с нулевой длиной содержимого необходимо явно вызвать метод GetRequestStream, а затем вызвать метод Close для возвращаемого потока без вызова метода Write...

Однако они не сообщают вам, были ли отправлены какие-либо данные, вы получите исключение при вызове метода Close («Эта операция не может быть выполнена после отправки запроса»). Итак, мне нужно было сделать это:

using (Stream httpWebRequestStream = httpWebRequest.GetRequestStream())
{
<other transmission code, including write if there's data>

    if (httpWebRequest.ContentLength == 0)
    {
        Log.Debug("httpWebRequest stream Close:");
        httpWebRequestStream.Close();
    }
}
  1. Утечки памяти

Я думаю, что в моем коде все еще могут быть некоторые, но я попытался улучшить их с помощью этого более позднего кода:

httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;

<handle response>

httpWebResponse.GetResponseStream().Close();
httpWebResponse.Close();
httpWebResponse = null;

httpWebRequest = null;

А это в блоке catch:

if (httpWebResponse != null)
{
    httpWebResponse.GetResponseStream().Close();
    httpWebResponse.Close();
    httpWebResponse = null;
}
if (httpWebRequest != null)
{
    httpWebRequest = null;
}
person hemisphire    schedule 29.04.2015