簡體   English   中英

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

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

基於這個先前的問題,我想看看不處理HttpClient object 是否會造成泄漏(確實如此,但這里沒有什么新東西)。 但是,我還發現,如果我不處理HttpClient object,則返回的HttpResponseMessage不會被垃圾收集。

這是測試。 我在這里提供了一個復制小提琴

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下編譯,output如下:

Alive: True
Alive: False

編輯:使用 .NET Core,我得到了預期的結果:

Alive: False
Alive: False

我的問題是,為什么HttpResponseMessage在我處理它之后仍然存在,但前提是我不處理它的創建者?

(查看HttpClient的來源,我發現確實存在對所持有的HttpResponseMessage的引用,但這深入到異步領域,讓我真正了解發生了什么( SetTaskCompleted -> TaskCompletionSource<>.TrySetResult() ))

首先,我們需要看看這個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);
}

暫無
暫無

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

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