简体   繁体   English

C# 弱引用 object 在“使用”块后存活

[英]C# Weak-referenced object alive after `using` block

Based on this previous question , I wanted to see if not disposing an HttpClient object creates leaks (which does, but nothing new here).基于这个先前的问题,我想看看不处理HttpClient object 是否会造成泄漏(确实如此,但这里没有什么新东西)。 However, what I've also found is that if I don't dispose a HttpClient object, the returned HttpResponseMessage is not garbage collected.但是,我还发现,如果我不处理HttpClient object,则返回的HttpResponseMessage不会被垃圾收集。

Here's the test.这是测试。 I've provided a 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();
        }
    }
}

Compiling under .NET Framework 4.7.2, The output is as follows:在.NET Framework 4.7.2下编译,output如下:

Alive: True
Alive: False

Edit: using .NET Core, I get the expected result:编辑:使用 .NET Core,我得到了预期的结果:

Alive: False
Alive: False

My question is, why HttpResponseMessage is still alive after I disposed it, but only if I don't dispose it's creator?我的问题是,为什么HttpResponseMessage在我处理它之后仍然存在,但前提是我不处理它的创建者?

(Looking at HttpClient 's sources I found that there is indeed a reference to the HttpResponseMessage being held, but this is deep into async land for me to really understand what's going on ( SetTaskCompleted -> TaskCompletionSource<>.TrySetResult() )) (查看HttpClient的来源,我发现确实存在对所持有的HttpResponseMessage的引用,但这深入到异步领域,让我真正了解发生了什么( SetTaskCompleted -> TaskCompletionSource<>.TrySetResult() ))

First of all, we need look at this MSDN - HttpClient Class .首先,我们需要看看这个MSDN - HttpClient Class

HttpClient is intended to be instantiated once per application, rather than per-use. HttpClient 旨在为每个应用程序实例化一次,而不是每次使用。 See Remarks.见备注。

Anyway, here is what you missed.无论如何,这就是你错过的。

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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM