Должен ли я явно закрыть ResponseStream асинхронного http-запроса? - PullRequest
2 голосов
/ 22 августа 2011

У меня есть рабочая роль Azure, которая, помимо прочих функций, выполняет некоторые HTTP-запросы каждые 80 секунд или около того. Это происходит постоянно. По мере того, как мы увеличиваем масштаб, он может делать намного больше HTTP-запросов, поэтому я написал код для использования BeginGetResponse, EndGetResponse и обратного вызова. Проблема в том, что ... у нас где-то утечка памяти. Когда этот процесс выполняется, он медленно, но верно теряет память, пока не закончится полностью. Иногда GC запускает и освобождает некоторые неиспользуемые объекты, но продолжает свой медленный нисходящий тренд.

Когда наш обратный вызов выполняется и мы завершаем запрос с помощью EndGetResponse (), мы не касаемся потока ответов. Все, что нам нужно знать, - это код состояния HTTP, который мы сохраняем для наших собственных записей. , Мы никогда не вызываем GetResponseStream () и впоследствии закрываем его. Мы делаем Закрываем () HttpWebResponse.

Мой вопрос: нужно ли что-то делать с потоком ответов, а затем закрыть () это? Не приведет ли это к утечке памяти? Все примеры MS / другие обсуждения SO, которые я видел, как-то связаны с потоком. Мне интересно, если мы должны добавить GetResponseStream (). Close () ...

Вот код:

// the request state class, passed along with async request
public class RequestState
{             
    public HttpWebRequest Request { get; set; }
    public HttpWebResponse Response { get; set; }

    // some other properties to track which request this is..
}

...... in some other class .....

// code to perform the request
public void DoHttpRequest() 
{
    HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://myurl.....");
    RequestState state = new RequestState(req); // this just sets the Request property on RequestState
    req.BeginGetResponse(OnRequestComplete, state);
}

// the callback, request has finished
public void OnRequestComplete(IAsyncResult result)
{
    RequestState state = (RequestState)result.AsyncState;
    HttpWebRequest req = state.Request;
    state.Response = (HttpWebResponse)req.EndGetResponse(result);

    // we do not care about the body of the response
    // all we want is the status code, which we store somewhere else..

    if (state.Response.StatusCode == HttpStatusCode.OK || state.Response.StatusCode == HttpStatusCode.Created)
    {
         // comm was successful
         // save this result code somewhere...
    }
    else if (state.Response.StatusCode == HttpStatusCode.RequestTimeout || state.Response.StatusCode == HttpStatusCode.GatewayTimeout)
    {
          // comm timed out
          // save this result code somewhere..
    }
    else
    {
          // something else, comm failed
          // save this result code somewhere..
    }

    // we've got the relevant data from the HttpWebResponse object, dispose of it
    state.Response.Close();
}

Спасибо!

Ответы [ 4 ]

1 голос
/ 22 августа 2011

Я включил Reflector (последняя версия .NET 4.0, используемая приложениями Azure): HttpWebResponse.Close закрывает поток, который будет возвращен GetResponseStream.

Звучит так, как будто есть проблема в другом месте.

Вкратце, закрытие потока должно также вызвать Abort для исходного HttpWebRequest, но логика довольно запутанная. Возможно, вы захотите попробовать вызвать Abort явно и посмотреть, не исчезнет ли использование памяти.

0 голосов
/ 24 августа 2011

Чтобы точно определить, что происходит, используйте новейшие инструменты профилирования для Windows Azure, см. Msdn - Профилирование приложения Windows Azure и используйте параметр профилирования памяти.

Вы можете получить новейшие инструменты от WebPI здесь

0 голосов
/ 23 августа 2011

Я столкнулся с очень похожей проблемой для вас. У меня было несколько рабочих ролей, которые периодически переходили в состояние, в котором Azure больше не мог связываться с ним, и они не перезапускались, как я ожидал, когда произойдет ошибка в экземпляре Azure.

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

Оказалось, что у нас был объект, который мы использовали довольно часто, и мы не называли его утилизировать, когда закончили.

Поэтому, отвечая на ваш вопрос, в качестве общего принципа, если у объекта есть метод dispose, когда вы закончите работу с ним, вы должны вызвать dispose.

0 голосов
/ 22 августа 2011

вы можете использовать оператор using для получения ответа, гарантируя его удаление!если вы не планируете читать содержимое потока снова, я не вижу никакого вреда в завершении!на второй мысли: в вашем обратном вызове вы уверены, что нет никаких исключений при попытке записать результат где-то?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...