繁体   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