【问题标题】:C# Weak-referenced object alive after `using` block`using` 块后 C# 弱引用对象存活
【发布时间】:2020-07-14 01:14:29
【问题描述】:

基于on this previous question,我想看看不释放HttpClient 对象是否会造成泄漏(确实如此,但这里没有什么新鲜事)。但是,我还发现,如果我不处置 HttpClient 对象,则返回的 HttpResponseMessage 不会被垃圾回收。

这是测试。我提供了一个reproducing fiddle here

using System;
using System.Net.Http;

namespace HttpClientTest
{
    internal static class Program
    {
        private static T CallInItsOwnScope<T>(Func<T> getter)
        {
            return getter();
        }

        private static void Main()
        {
            var client = new HttpClient();
            var wRef2 = CallInItsOwnScope(() =>
            {
                using (var response = client.GetAsync(new Uri("https://postman-echo.com/get?foo1=bar1&foo2=bar2")).Result)
                {
                    return new WeakReference(response);
                }
            });
            GC.Collect();
            GC.WaitForPendingFinalizers();
            Console.WriteLine($"Alive: {wRef2.IsAlive}");

            client.Dispose();

            GC.Collect();
            GC.WaitForPendingFinalizers();
            Console.WriteLine($"Alive: {wRef2.IsAlive}");

            Console.ReadKey();
        }
    }
}

在.NET Framework 4.7.2下编译,输出如下:

Alive: True
Alive: False

编辑: 使用 .NET Core,我得到了预期的结果:

Alive: False
Alive: False

我的问题是,为什么 HttpResponseMessage 在我处置后仍然活着,但前提是我不处置它的创建者?

(查看HttpClient 的来源,我发现确实有对HttpResponseMessage 的引用,但这对我来说深入到异步领域才能真正理解发生了什么(SetTaskCompleted -> @ 987654334@))

【问题讨论】:

  • 你为什么要Dispose你的HttpClient。一般的建议是让他们永远活着。
  • 我试图理解为什么HttpResponse 对象会泄漏。我不担心HttpClient,事实上,我担心过于频繁地处理它会导致套接字耗尽。
  • 我收到了FalseFalse,因此如果您希望其他人看到您所看到的内容,这里缺少一些细节。
  • 我有一个普通的 .net framework 4.7.2 控制台应用程序,它返回上面的结果。对于这两种情况,使用 .net 核心控制台应用程序都会返回 false。
  • 达米安,您应该至少等一会才开始结束问题。这是一个小提琴给你看。 dotnetfiddle.net/Xo6iKu

标签: c# .net garbage-collection


【解决方案1】:

首先,我们需要看看这个MSDN - HttpClient Class

HttpClient 旨在为每个应用程序实例化一次,而不是每次使用。见备注。

无论如何,这就是你错过的。

public void CallServiceTest()
{
    var wRef2 = CallInItsOwnScope(() =>
    {
        // HttpClient -> HttpMessageInvoker(IDisposable), so it can be disposed.
        using (var client = new HttpClient())
        { 
            using (var response = client.GetAsync(new Uri("https://postman-echo.com/get?foo1=bar1&foo2=bar2")).Result)
            {
                return new WeakReference(response);
            }
        }
    });
    GC.Collect();
    GC.WaitForPendingFinalizers();
    Assert.IsFalse(wRef2.IsAlive);
}

【讨论】:

  • 我重新表述了这个问题。我的实际问题是HttpResponseMessage 在不处置其创建者时泄漏。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-28
  • 1970-01-01
  • 1970-01-01
  • 2013-09-08
  • 1970-01-01
  • 2016-10-01
  • 1970-01-01
相关资源
最近更新 更多