Как HttpWebRequest.GetResponseAsync может завершиться с ошибкой OutOfMemoryException?

Я пишу код, который обрабатывает данные из веб-службы. Сам HTTP-запрос находится в методе async, который выглядит примерно так:

private async Task<IEnumerable<string[]>> GenericGrab(string query)
{
    var req = WebRequest.Create(new Uri("http://example.org/" + query)) as HttpWebRequest;
    HttpWebResponse res;
    try
    {
        res = (HttpWebResponse) await req.GetResponseAsync(); // BOOM!
    }
    // Boring exception handlers skipped
    StreamReader read = new StreamReader(res.GetResponseStream());
    string l;
    while (true) {
        l = await read.ReadLineAsync().ConfigureAwait(false);
        if (l == null) break;
        // Process lines here
    }
    // Return result of processing
}

Этот метод используется для различных запросов к веб-службе. Он работает большую часть времени, но, кажется, терпит неудачу, когда есть немного больше данных (однако все ответы намного меньше 1 МБ). В случае сбоя вызов GetResponseAsync с пометкой BOOM! в коде приводит к OutOfMemoryException в mscorlib.ni.dll. Неудивительно, что стек вызовов не слишком информативен:

myapp.exe!MyApp.App.InitializeComponent.AnonymousMethod__1e(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e) Line 50  C#
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    mscorlib.ni.dll!System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.RoReportUnhandledError(System.Runtime.InteropServices.WindowsRuntime.IRestrictedErrorInfo error)    Unknown
    mscorlib.ni.dll!System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.ReportUnhandledError(System.Exception e)    Unknown
    System.Runtime.WindowsRuntime.NI.DLL!System.Threading.WinRTSynchronizationContext.Invoker.InvokeCore()  Unknown
    System.Runtime.WindowsRuntime.NI.DLL!System.Threading.WinRTSynchronizationContext.Invoker.InvokeInContext(object thisObj)   Unknown
    mscorlib.ni.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)    Unknown
    mscorlib.ni.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)    Unknown
    System.Runtime.WindowsRuntime.NI.DLL!System.Threading.WinRTSynchronizationContext.Invoker.Invoke()  Unknown

(Отладчик ломается в App.g.i.cs, который был сгенерирован VS; код кажется универсальным перехватчиком исключений.)

Я не понимаю, что здесь может происходить... насколько я понимаю API, размер ответа не должен иметь значения, потому что он обрабатывается как поток (с использованием GetResponseStream), и исключение все равно выдается перед этим. .

Может ли кто-нибудь объяснить мне, что может быть причиной этого?


person Jan Krüger    schedule 11.04.2015    source источник


Ответы (1)


Попробуйте избавиться от переменной «res» и скажите, лучше ли это. В прошлом у меня было несколько ошибок, потому что я забыл сделать это с объектами HttpWebResponse.

person Nicolas Dorier    schedule 11.04.2015
comment
Насколько я понимаю, res должен автоматически удаляться при выходе из области действия метода. Разве это не то, что происходит? В любом случае, я только что попробовал это, и, к сожалению, это ничего не изменило. - person Jan Krüger; 11.04.2015
comment
Это не. После того, как он выйдет из области видимости, объект будет очищен сборщиком мусора, но вы не знаете, когда. В моем случае возникло много проблем, потому что внутренне HttpWebRequest отслеживал количество открытых ответов и блокировался после определенного порога ограничения соединения, что вызывало у меня проблемы с взаимоблокировкой. За исключением этого, ваш код выглядит нормально... Попробуйте, я не думаю, что он что-то решит, хотя req.GetResponseAsync().ConfigureAwait(false); и res.GetResponseStreamAsync().ConfigureAwait(false); - person Nicolas Dorier; 12.04.2015
comment
Я действительно пробовал это, прежде чем публиковать вопрос ... к сожалению, не помогло. Кстати, ошибка обычно возникает при втором запросе (но не всегда... если данных немного меньше, я могу сделать десятки запросов без каких-либо проблем). - person Jan Krüger; 13.04.2015
comment
Последняя ставка, вы пытались установить для httpwebrequest.allowreadstreambuffering значение false ? В любом случае вам следует выполнить ConfigureAwait(false), если вы не хотите, чтобы в prod возник странный тупик. - person Nicolas Dorier; 14.04.2015