簡體   English   中英

使用HttpClient異步方法C#時發生內存泄漏

[英]Memory leaks when using HttpClient Async methods c#

以下代碼每秒被調用多次。 如果_client.PostJsonAsync拋出OperationCanceledException(例如,由於超時),則返回Task.FromResult(default(T)),但是在這種情況下,內存使用率(和CPU使用率)迅速開始攀升,直到拋出OutOfMemoryExceptions(甚至當未引發異常時,內存似乎總是在爬升,盡管速度要慢得多。 代碼是否存在任何問題(或其過度使用),可能導致內存泄漏?

    private async Task<T> GetResponse<T>(Dictionary<string, object> args, string method)
    {
        try
        {
            var response = await _client.PostAsJsonAsync(method, args);


            return await Deserialise<T>(response.Content); 

        }
        catch (OperationCanceledException)
        {
            return await Task.FromResult(default(T));
        }
    }

    private async Task<T> Deserialise<T>(HttpContent content)
    {
        using (var stream = await content.ReadAsStreamAsync())
        using (var streamReader = new StreamReader(stream))
        using (var reader = new JsonTextReader(streamReader))
        {
            var serializer = new JsonSerializer();
            try
            {
                return serializer.Deserialize<T>(reader);
            }
            catch (JsonSerializationException e)
            {
                throw new ClientException("Failed to deserialize object, see inner exception and content for more details", e) { Content = reader.ReadAsString() };
            }
        }
    }

我可以指出兩點使您的內存使用量增加:

  • 正如Nkosi在評論中指出的那樣, PostAsJsonAsync返回類型是HttpResponseMessage ,它實現了IDisposable因此您應該對其進行處理,只需在其周圍添加using語句即可。
    這是您的代碼泄漏的地方,也是即使沒有引發異常時內存使用量也會增加的原因。

  • 引發異常時,似乎您的內存使用量增長更快的原因是,除了這種情況下的第一個問題之外,您還使用Task.FromResult創建了許多新任務,這給您的內存使用量增加了壓力。
    盡管它似乎沒有泄漏,但仍會使GC更加努力工作,這就是為什么我建議您緩存您返回的任務(您可以重復使用同一任務實例,因為您總是返回相同的值),甚至更好根本沒有新任務。
    由於您的方法已被標記為async您可以立即返回default(T) ,並且編譯器將為您生成狀態機並將其包裝在任務中(無論如何,它都會這樣做,沒有理由創建並等待新任務)。

您修改后的代碼應如下所示:

private async Task<T> GetResponse<T>(Dictionary<string, object> args, string method)
{
    try
    {
        using(var response = await _client.PostAsJsonAsync(method, args))
        {
            return await Deserialise<T>(response.Content); 
        }
    }
    catch (OperationCanceledException)
    {
        return default(T);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM