使用HttpClient异步方法时内存泄漏c#

问题描述 投票:0回答:1

以下代码每秒调用多次。如果_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() };
            }
        }
    }
c# memory-leaks async-await httpclient
1个回答
3
投票

我可以指出两个使你的内存使用率攀升的事情:

  • 正如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);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.