Runtime: HttpMessageInvoker/SocketsHttpHandler appears to be leaking streams / sockets

Created on 11 Nov 2020  路  7Comments  路  Source: dotnet/runtime

Description

While debugging memory related issues in my project, I discovered a large number of sockets and streams in my process finalization queue. The following program reproduces the issue:

```c#
static void Main(string[] args)
{
var sh = new SocketsHttpHandler();

for (int i = 0; i < 50; i++)
{
    using (var hm = new HttpMessageInvoker(sh, false))
    {
        var result = hm.SendAsync(new HttpRequestMessage(HttpMethod.Get, "https://www.microsoft.com"), System.Threading.CancellationToken.None).GetAwaiter().GetResult();

        Console.WriteLine(result);
    }
}

sh.Dispose();

Console.WriteLine("Finished");
Console.ReadLine();

}

This program results in the following finalization queue statistics:

0:000> !fq -allready
SyncBlocks to be cleaned up: 0
Free-Threaded Interfaces to be released: 0
MTA Interfaces to be released: 0

STA Interfaces to be released: 0

generation 0 has 0 finalizable objects (0000028471302830->0000028471302830)
generation 1 has 0 finalizable objects (0000028471302830->0000028471302830)
generation 2 has 0 finalizable objects (0000028471302830->0000028471302830)
Finalizable but not rooted:
Ready for finalization 1594 objects (0000028471302830->0000028471305A00)
Statistics for all finalizable objects that are no longer rooted:
MT Count TotalSize Class Name
00007ffce9b2ff28 1 24 System.Threading.TimerHolder
00007ffce9b2c7e0 1 24 System.WeakReference1[[System.Net.Http.HttpConnectionPoolManager, System.Net.Http]] 00007ffce9b84760 1 32 System.Threading.TimerQueue+AppDomainTimerSafeHandle 00007ffce9cc6f90 1 40 System.Net.Security.SafeCredentialReference 00007ffce9b43c90 1 40 Interop+WinHttp+SafeWinHttpHandle 00007ffce9ccdfb0 1 48 System.Net.Security.SafeFreeCredential_SECURITY 00007ffce9d196f8 1 56 System.Runtime.CompilerServices.ConditionalWeakTable2+Container[[System.Byte[][], System.Private.CoreLib],[System.Object, System.Private.CoreLib]]
00007ffce9c94618 1 56 System.Runtime.CompilerServices.ConditionalWeakTable2+Container[[System.Threading.Tasks.TaskScheduler, System.Private.CoreLib],[System.Object, System.Private.CoreLib]] 00007ffce9b4fec8 1 56 System.Runtime.CompilerServices.ConditionalWeakTable2+Container[[System.Char[][], System.Private.CoreLib],[System.Object, System.Private.CoreLib]]
00007ffce9d0c0a8 2 64 Internal.Cryptography.Pal.Native.SafeChainEngineHandle
00007ffce9b628b8 2 80 System.Gen2GcCallback
00007ffce9ccc068 4 128 Microsoft.Win32.SafeHandles.SafeAccessTokenHandle
00007ffce9bc5cd8 5 160 Internal.Win32.SafeHandles.SafeRegistryHandle
00007ffce9c72da8 3 168 System.Threading.ThreadPoolWorkQueueThreadLocals
00007ffce9d35bc8 1 184 System.Net.NetEventSource
00007ffce9cc9810 1 184 System.Collections.Concurrent.CDSCollectionETWBCLProvider
00007ffce9cabe90 1 184 System.Net.NetEventSource
00007ffce9ba82f8 1 184 System.Net.NetEventSource
00007ffce9ba6dc8 1 184 System.Net.NetEventSource
00007ffce9b846a8 1 184 System.Diagnostics.Tracing.FrameworkEventSource
00007ffce9b4e9d8 1 184 System.Buffers.ArrayPoolEventSource
00007ffce9af2920 1 184 System.Net.NetEventSource
00007ffce9ab2f80 1 184 System.Diagnostics.Tracing.NativeRuntimeEventSource
00007ffce9bc2688 1 192 System.Threading.Tasks.TplEventSource
00007ffce9ba6ab0 1 208 System.Net.NameResolutionTelemetry
00007ffce9bae210 1 280 System.Net.Sockets.SocketsTelemetry
00007ffce9b231b8 1 296 System.Net.Http.HttpTelemetry
00007ffce9cc0d78 1 360 System.Net.Security.NetSecurityTelemetry
00007ffce9ab0b68 15 360 System.WeakReference1[[System.Diagnostics.Tracing.EventSource, System.Private.CoreLib]] 00007ffce9a87758 1 368 System.Diagnostics.Tracing.RuntimeEventSource 00007ffce9a6a8a8 7 504 System.Threading.Thread 00007ffce9d10c68 50 1200 System.WeakReference1[[System.Net.Http.HttpConnection, System.Net.Http]]
00007ffce9d0e200 50 1600 Microsoft.Win32.SafeHandles.SafeX509ChainHandle
00007ffce9d0c1a0 50 1600 Internal.Cryptography.Pal.Native.SafeCertStoreHandle
00007ffce9cee490 50 1600 System.Net.Security.SafeFreeCertContext
00007ffce9d0d510 51 1632 Internal.Cryptography.Pal.Native.SafeLocalAllocHandle
00007ffce9ba8d10 50 2400 System.Net.Sockets.SafeSocketHandle
00007ffce9ba42a8 50 2400 System.Net.Sockets.NetworkStream
00007ffce9cceaa8 50 2800 System.Net.Security.SafeDeleteSslContext
00007ffce9a88178 30 3360 System.Diagnostics.Tracing.EventSource+OverideEventProvider
00007ffce9bace30 150 4800 System.Threading.PreAllocatedOverlapped
00007ffce9cae688 201 6432 System.Net.Security.SafeFreeContextBuffer_SECURITY
00007ffce9ba3db0 50 6800 System.Net.Sockets.Socket
00007ffce9b87e78 50 8400 System.Net.Http.HttpConnection
00007ffce9b8f550 50 11600 System.Net.Security.SslStream
00007ffce9bab7d8 50 16800 System.Net.Sockets.SocketAsyncEventArgs
00007ffce9d03180 450 18000 Internal.Cryptography.Pal.Native.SafeCertContextHandle
00007ffce9bac170 100 38400 System.Net.Sockets.Socket+AwaitableSocketAsyncEventArgs
Total 1594 objects
```

My expectation would be that the generated streams and sockets would be deterministically cleaned up, and not left to finalization.

Configuration

.NET 5.0, Windows 10 20H2, both x86 and x64

Regression?

Similar, but not precisely identical, finalization queues are generated under .NET 3.1, so I believe this problem exists there as well.

Other information

I would be excited to learn that I'm doing something monumentally wrong with the above API. I know of no workarounds, and I believe this behavior is negatively impacting the memory utilization characteristics of my project.

area-System.Net.Http untriaged

Most helpful comment

Why would a finalizable object show up in the finalization queue after SuppressFinalize has been called on it?

GC.SuppressFinalize just sets a bit in the object header. It doesn't remove it from the finalization queue.

https://github.com/dotnet/runtime/blob/29e9b5b7fd95231d9cd9d3ae351404e63cbb6d5a/src/coreclr/src/vm/comutilnative.cpp#L1225-L1228

gc.cpp is too large for GitHub to let me link into it, but you can see its implementation here:
https://raw.githubusercontent.com/dotnet/runtime/29e9b5b7fd95231d9cd9d3ae351404e63cbb6d5a/src/coreclr/src/gc/gc.cpp

void GCHeap::SetFinalizationRun (Object* obj)
{
    ((CObjectHeader*)obj)->GetHeader()->SetBit(BIT_SBLK_FINALIZER_RUN);
}

All 7 comments

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.




Issue meta data

















Issue content: ### Description
While debugging memory related issues in my project, I discovered a large number of sockets and streams in my process finalization queue. The following program reproduces the issue:

```c#
static void Main(string[] args)
{
var sh = new SocketsHttpHandler();

for (int i = 0; i < 50; i++)
{
    using (var hm = new HttpMessageInvoker(sh, false))
    {
        var result = hm.SendAsync(new HttpRequestMessage(HttpMethod.Get, "https://www.microsoft.com"), System.Threading.CancellationToken.None).GetAwaiter().GetResult();

        Console.WriteLine(result);
    }
}

sh.Dispose();

Console.WriteLine("Finished");
Console.ReadLine();

}

This program results in the following finalization queue statistics:

0:000> !fq -allready
SyncBlocks to be cleaned up: 0
Free-Threaded Interfaces to be released: 0
MTA Interfaces to be released: 0

STA Interfaces to be released: 0

generation 0 has 0 finalizable objects (0000028471302830->0000028471302830)
generation 1 has 0 finalizable objects (0000028471302830->0000028471302830)
generation 2 has 0 finalizable objects (0000028471302830->0000028471302830)
Finalizable but not rooted:
Ready for finalization 1594 objects (0000028471302830->0000028471305A00)
Statistics for all finalizable objects that are no longer rooted:
MT Count TotalSize Class Name
00007ffce9b2ff28 1 24 System.Threading.TimerHolder
00007ffce9b2c7e0 1 24 System.WeakReference1[[System.Net.Http.HttpConnectionPoolManager, System.Net.Http]] 00007ffce9b84760 1 32 System.Threading.TimerQueue+AppDomainTimerSafeHandle 00007ffce9cc6f90 1 40 System.Net.Security.SafeCredentialReference 00007ffce9b43c90 1 40 Interop+WinHttp+SafeWinHttpHandle 00007ffce9ccdfb0 1 48 System.Net.Security.SafeFreeCredential_SECURITY 00007ffce9d196f8 1 56 System.Runtime.CompilerServices.ConditionalWeakTable2+Container[[System.Byte[][], System.Private.CoreLib],[System.Object, System.Private.CoreLib]]
00007ffce9c94618 1 56 System.Runtime.CompilerServices.ConditionalWeakTable2+Container[[System.Threading.Tasks.TaskScheduler, System.Private.CoreLib],[System.Object, System.Private.CoreLib]] 00007ffce9b4fec8 1 56 System.Runtime.CompilerServices.ConditionalWeakTable2+Container[[System.Char[][], System.Private.CoreLib],[System.Object, System.Private.CoreLib]]
00007ffce9d0c0a8 2 64 Internal.Cryptography.Pal.Native.SafeChainEngineHandle
00007ffce9b628b8 2 80 System.Gen2GcCallback
00007ffce9ccc068 4 128 Microsoft.Win32.SafeHandles.SafeAccessTokenHandle
00007ffce9bc5cd8 5 160 Internal.Win32.SafeHandles.SafeRegistryHandle
00007ffce9c72da8 3 168 System.Threading.ThreadPoolWorkQueueThreadLocals
00007ffce9d35bc8 1 184 System.Net.NetEventSource
00007ffce9cc9810 1 184 System.Collections.Concurrent.CDSCollectionETWBCLProvider
00007ffce9cabe90 1 184 System.Net.NetEventSource
00007ffce9ba82f8 1 184 System.Net.NetEventSource
00007ffce9ba6dc8 1 184 System.Net.NetEventSource
00007ffce9b846a8 1 184 System.Diagnostics.Tracing.FrameworkEventSource
00007ffce9b4e9d8 1 184 System.Buffers.ArrayPoolEventSource
00007ffce9af2920 1 184 System.Net.NetEventSource
00007ffce9ab2f80 1 184 System.Diagnostics.Tracing.NativeRuntimeEventSource
00007ffce9bc2688 1 192 System.Threading.Tasks.TplEventSource
00007ffce9ba6ab0 1 208 System.Net.NameResolutionTelemetry
00007ffce9bae210 1 280 System.Net.Sockets.SocketsTelemetry
00007ffce9b231b8 1 296 System.Net.Http.HttpTelemetry
00007ffce9cc0d78 1 360 System.Net.Security.NetSecurityTelemetry
00007ffce9ab0b68 15 360 System.WeakReference1[[System.Diagnostics.Tracing.EventSource, System.Private.CoreLib]] 00007ffce9a87758 1 368 System.Diagnostics.Tracing.RuntimeEventSource 00007ffce9a6a8a8 7 504 System.Threading.Thread 00007ffce9d10c68 50 1200 System.WeakReference1[[System.Net.Http.HttpConnection, System.Net.Http]]
00007ffce9d0e200 50 1600 Microsoft.Win32.SafeHandles.SafeX509ChainHandle
00007ffce9d0c1a0 50 1600 Internal.Cryptography.Pal.Native.SafeCertStoreHandle
00007ffce9cee490 50 1600 System.Net.Security.SafeFreeCertContext
00007ffce9d0d510 51 1632 Internal.Cryptography.Pal.Native.SafeLocalAllocHandle
00007ffce9ba8d10 50 2400 System.Net.Sockets.SafeSocketHandle
00007ffce9ba42a8 50 2400 System.Net.Sockets.NetworkStream
00007ffce9cceaa8 50 2800 System.Net.Security.SafeDeleteSslContext
00007ffce9a88178 30 3360 System.Diagnostics.Tracing.EventSource+OverideEventProvider
00007ffce9bace30 150 4800 System.Threading.PreAllocatedOverlapped
00007ffce9cae688 201 6432 System.Net.Security.SafeFreeContextBuffer_SECURITY
00007ffce9ba3db0 50 6800 System.Net.Sockets.Socket
00007ffce9b87e78 50 8400 System.Net.Http.HttpConnection
00007ffce9b8f550 50 11600 System.Net.Security.SslStream
00007ffce9bab7d8 50 16800 System.Net.Sockets.SocketAsyncEventArgs
00007ffce9d03180 450 18000 Internal.Cryptography.Pal.Native.SafeCertContextHandle
00007ffce9bac170 100 38400 System.Net.Sockets.Socket+AwaitableSocketAsyncEventArgs
Total 1594 objects
```

My expectation would be that the generated streams and sockets would be deterministically cleaned up, and not left to finalization.

Configuration

.NET 5.0, Windows 10 20H2, both x86 and x64

Regression?

Similar, but not precisely identical, finalization queues are generated under .NET 3.1, so I believe this problem exists there as well.

Other information

I would be excited to learn that I'm doing something monumentally wrong with the above API. I know of no workarounds, and I believe this behavior is negatively impacting the memory utilization characteristics of my project.

Issue author: brporter
Assignees: -
Milestone: -

You need to dispose of result.

HttpMessageInvoker's behavior is just like HttpClient's ResponseHeadersReceived behavior, in that SendAsync will return to you once headers have been received, handing back an HttpResponseMessage that let's you read the response body from the network. If you don't dispose of that HttpResponseMessage (or the Stream you get from it), you're abandoning the request to only be cleaned up when the system realizes it's no longer being used, which is finalization.

Dispose'ing of the handler / HttpMessageInvoker isn't sufficient. It explicitly doesn't interrupt response streams actively being used by a consumer.

Yes! That's a silly mistake on my part. However, I'm still winding up with streams and sockets left over (although not nearly as many as I had previously).

0:000> !fq -allready
SyncBlocks to be cleaned up: 0
Free-Threaded Interfaces to be released: 0
MTA Interfaces to be released: 0
STA Interfaces to be released: 0
----------------------------------
generation 0 has 169 finalizable objects (000001106B754F50->000001106B755498)
generation 1 has 0 finalizable objects (000001106B754F50->000001106B754F50)
generation 2 has 0 finalizable objects (000001106B754F50->000001106B754F50)
Finalizable but not rooted:  0000011053140900 0000011053140ec8 00000110531494a0 00000110531496c8 000001105314c608 000001105314c838 000001105314cad8 000001105314cb30 000001105314cbf8 000001105314cc60 000001105314cc88 000001105314dc18 000001105318ffc0 0000011053190140 0000011053192b60 0000011053192c88 0000011053194590 0000011053196a80 0000011053196dc8 0000011053196de8 0000011053196f48 0000011053197298 00000110531972b8 0000011053198968 0000011053198e00 00000110531991c0 0000011053199368 0000011053199fa8 000001105319aef0 000001105319b160 000001105319b288 000001105319b6c8 000001105319b7e8 000001105319b930 000001105319bc78 000001105319c0a0 000001105319c2e0 000001105319c7e0 000001105319ceb0 000001105319d080 000001105319db28 000001105319df58 000001105319e320 000001105319e938 000001105319e958 000001105319e9b0 000001105319ea38 000001105319ec20 000001105319ece8 000001105319efb0 000001105319f100 000001105319f208 000001105319f440 00000110531a1958 00000110531a3750 00000110531ae898 00000110531c3460 00000110531c35f0 00000110531c3770 00000110531c37d8 00000110531c3800 00000110531c3858 00000110531c38c0 00000110531c38e8 0000011053190d30 0000011053190eb0 00000110531c6058 00000110531ba250 00000110531ba2e8 00000110531ba6c0 00000110531ba6e0 00000110531ba850 00000110531ba9f8 00000110531baaf0 00000110531bac98 00000110531bb170 00000110531c8e38 00000110531c90a8 00000110531c91d0 00000110531c9570 00000110531c9690 00000110531c97d8 00000110531c9858 00000110531c9918 00000110531c9a30 00000110531c9b48 00000110531c9cf0 00000110531c9d10 00000110531c9d38 00000110531c9d98 00000110531c9db8 00000110531c9de0 00000110531c9f00 00000110531ca020 00000110531ca128 00000110531ca248 00000110531cc360 00000110531d7798 00000110531f4058 00000110531f4090 
Ready for finalization 0 objects (000001106B755498->000001106B755498)
Statistics for all finalizable objects that are no longer rooted:
              MT    Count    TotalSize Class Name
00007ffceb7843e8        1           32 Microsoft.Win32.SafeHandles.SafeLibraryHandle
00007ffceb8bfb98        2           48 System.WeakReference`1[[System.Net.Http.HttpConnection, System.Net.Http]]
00007ffceb7cd308        1           56 System.Threading.ThreadPoolWorkQueueThreadLocals
00007ffceb8bd088        2           64 Microsoft.Win32.SafeHandles.SafeX509ChainHandle
00007ffceb8bc3e0        2           64 Internal.Cryptography.Pal.Native.SafeLocalAllocHandle
00007ffceb8bb0a8        2           64 Internal.Cryptography.Pal.Native.SafeCertStoreHandle
00007ffceb8a8498        2           64 System.Net.Security.SafeFreeCertContext
00007ffceb8dbf18        2           80 System.Gen2GcCallback
00007ffceb6e2a78        2           80 Microsoft.Win32.SafeHandles.SafeLocalAllocHandle
00007ffceb8b90d0        3           96 Microsoft.Win32.SafeHandles.SafeLibraryHandle
00007ffceb78fd00        3           96 Internal.Win32.SafeHandles.SafeRegistryHandle
00007ffceb8a0df0        2          112 System.Net.Security.SafeDeleteContext_SECURITY
00007ffceb768e30        2          112 System.Net.Sockets.ExposedSocketNetworkStream
00007ffceb87d3e0        4          128 Microsoft.Win32.SafeHandles.SafeAccessTokenHandle
00007ffceb785eb0        4          160 System.Net.Sockets.SafeSocketHandle+InnerSafeCloseSocket
00007ffceb635650        3          216 System.Threading.Thread
00007ffceb7863e8        4          256 System.Net.Sockets.SafeSocketHandle
00007ffceb76ab18        8          256 System.Threading.PreAllocatedOverlapped
00007ffceb760c98        4          416 System.Net.Sockets.Socket
00007ffceb764898        2          464 System.Net.Security.SslStream
00007ffceb872ae0       17          544 System.Net.Security.SafeFreeContextBuffer_SECURITY
00007ffceb768538        2          720 System.Net.Sockets.SocketAsyncEventArgs
00007ffceb768738        2          752 System.Net.Http.ConnectHelper+ConnectEventArgs
00007ffceb8b29c8       20          800 Internal.Cryptography.Pal.Native.SafeCertContextHandle
00007ffceb7ea968        4         1600 System.Net.Sockets.Socket+AwaitableSocketAsyncEventArgs

For a bit more detail, I've actually got a proxy project I'm working on that is showing positively abysmal memory utilization characteristics, and an enormous finalization queue filled with streams and sockets that weren't disposed of. This attempt at a repro was actually me simplifying that implementation to isolate what I think the problem is.

For clarity, and in the hopes I'm doing something else silly, here is an updated repro and corresponding finalization queue dump:

Repro:
```c#
static void Main(string[] args)
{
var sh = new SocketsHttpHandler();

for (int i = 0; i < 50; i++)
{
    using (var hm = new HttpMessageInvoker(sh, false))
    {
        using (var result = hm.SendAsync(new HttpRequestMessage(HttpMethod.Get, "https://www.microsoft.com"), System.Threading.CancellationToken.None).GetAwaiter().GetResult())
        {
            Console.WriteLine(result);
        }
    }
}

sh.Dispose();

Console.WriteLine("Finished");
Console.ReadLine();

}

Finalization queue statistics:

0:000> !fq -allready
SyncBlocks to be cleaned up: 0
Free-Threaded Interfaces to be released: 0
MTA Interfaces to be released: 0

STA Interfaces to be released: 0

generation 0 has 177 finalizable objects (0000029036F0E5E0->0000029036F0EB68)
generation 1 has 0 finalizable objects (0000029036F0E5E0->0000029036F0E5E0)
generation 2 has 0 finalizable objects (0000029036F0E5E0->0000029036F0E5E0)
Finalizable but not rooted: 000002901e620900 000002901e620ec8 000002901e6294a0 000002901e6296c8 000002901e62c608 000002901e62c838 000002901e62cad8 000002901e62cb30 000002901e62cbf8 000002901e62cc60 000002901e62cc88 000002901e62dc18 000002901e66ffc0 000002901e670140 000002901e672b60 000002901e672c88 000002901e674590 000002901e676a80 000002901e676dc8 000002901e676de8 000002901e676f48 000002901e677298 000002901e6772b8 000002901e678968 000002901e678e00 000002901e6791c0 000002901e679368 000002901e679fa8 000002901e67aef0 000002901e67b160 000002901e67b288 000002901e67b6c8 000002901e67b7e8 000002901e67b930 000002901e67bc78 000002901e67c0a0 000002901e67c2e0 000002901e67c7e0 000002901e67ceb0 000002901e67d080 000002901e67db28 000002901e67df58 000002901e67e320 000002901e67e938 000002901e67e958 000002901e67e9b0 000002901e67ea38 000002901e67ec20 000002901e67ece8 000002901e67efb0 000002901e67f100 000002901e67f208 000002901e67f440 000002901e681958 000002901e683358 000002901e683750 000002901e68e890 000002901e6a2e48 000002901e6a2fd8 000002901e6a3158 000002901e6a31c0 000002901e6a31e8 000002901e6a3240 000002901e6a32a8 000002901e6a32d0 000002901e670d30 000002901e670eb0 000002901e69b418 000002901e69b4b0 000002901e69b888 000002901e69b8a8 000002901e69ba18 000002901e69bbc0 000002901e69bcb8 000002901e69be60 000002901e6ac0e8 000002901e6acff0 000002901e6ad260 000002901e6ad388 000002901e6b17b8 000002901e6b18d8 000002901e6b1a20 000002901e6b1aa0 000002901e6b1b60 000002901e6b1c78 000002901e6b1d90 000002901e6b1f38 000002901e6b1f58 000002901e6b1f80 000002901e6b1ff8 000002901e6b2018 000002901e6b2040 000002901e6b2160 000002901e6b2268 000002901e6b2370 000002901e6b2490 000002901e6b45e0
Ready for finalization 0 objects (0000029036F0EB68->0000029036F0EB68)
Statistics for all finalizable objects that are no longer rooted:
MT Count TotalSize Class Name
00007ffceee243e8 1 32 Microsoft.Win32.SafeHandles.SafeLibraryHandle
00007ffceef5fb98 2 48 System.WeakReference1[[System.Net.Http.HttpConnection, System.Net.Http]] 00007ffceef7b6d8 1 56 System.Runtime.CompilerServices.ConditionalWeakTable2+Container[[System.Byte[][], System.Private.CoreLib],[System.Object, System.Private.CoreLib]]
00007ffceef5d088 2 64 Microsoft.Win32.SafeHandles.SafeX509ChainHandle
00007ffceef5c3e0 2 64 Internal.Cryptography.Pal.Native.SafeLocalAllocHandle
00007ffceef5b0a8 2 64 Internal.Cryptography.Pal.Native.SafeCertStoreHandle
00007ffceef48498 2 64 System.Net.Security.SafeFreeCertContext
00007ffceef7bf18 2 80 System.Gen2GcCallback
00007ffceed82a78 2 80 Microsoft.Win32.SafeHandles.SafeLocalAllocHandle
00007ffceef590d0 3 96 Microsoft.Win32.SafeHandles.SafeLibraryHandle
00007ffceee2fd00 3 96 Internal.Win32.SafeHandles.SafeRegistryHandle
00007ffceef40df0 2 112 System.Net.Security.SafeDeleteContext_SECURITY
00007ffceee08e30 2 112 System.Net.Sockets.ExposedSocketNetworkStream
00007ffceef1d3e0 4 128 Microsoft.Win32.SafeHandles.SafeAccessTokenHandle
00007ffceee25eb0 4 160 System.Net.Sockets.SafeSocketHandle+InnerSafeCloseSocket
00007ffceee263e8 4 256 System.Net.Sockets.SafeSocketHandle
00007ffceee0ab18 8 256 System.Threading.PreAllocatedOverlapped
00007ffceee00c98 4 416 System.Net.Sockets.Socket
00007ffceee04898 2 464 System.Net.Security.SslStream
00007ffceef12ae0 17 544 System.Net.Security.SafeFreeContextBuffer_SECURITY
00007ffceee08538 2 720 System.Net.Sockets.SocketAsyncEventArgs
00007ffceee08738 2 752 System.Net.Http.ConnectHelper+ConnectEventArgs
00007ffceef529c8 20 800 Internal.Cryptography.Pal.Native.SafeCertContextHandle
00007ffceee8a968 4 1600 System.Net.Sockets.Socket+AwaitableSocketAsyncEventArgs
Total 97 objects
```

Objects that show up on that list may have already been disposed and had GC.SuppressFinalize called. finalizequeue -allready doesn't screen those out.

@stephentoub Thanks for getting back to me. Why would a finalizable object show up in the finalization queue after SuppressFinalize has been called on it? Is this just an artifact of the way fanalizequeue lists the the contents of the finalization queue?

I'll close this issue.

Why would a finalizable object show up in the finalization queue after SuppressFinalize has been called on it?

GC.SuppressFinalize just sets a bit in the object header. It doesn't remove it from the finalization queue.

https://github.com/dotnet/runtime/blob/29e9b5b7fd95231d9cd9d3ae351404e63cbb6d5a/src/coreclr/src/vm/comutilnative.cpp#L1225-L1228

gc.cpp is too large for GitHub to let me link into it, but you can see its implementation here:
https://raw.githubusercontent.com/dotnet/runtime/29e9b5b7fd95231d9cd9d3ae351404e63cbb6d5a/src/coreclr/src/gc/gc.cpp

void GCHeap::SetFinalizationRun (Object* obj)
{
    ((CObjectHeader*)obj)->GetHeader()->SetBit(BIT_SBLK_FINALIZER_RUN);
}
Was this page helpful?
0 / 5 - 0 ratings