CancellationToken registration leak, regression
See original GitHub issueDescribe the bug
After updating to SqlClient 5.0.1, we observe a memory leak in our application. Memory dumps show a huge amount of CancellationTokenSource+CallbackNode entries (we had a dump with 2 GB of those), referencing SqlCommand objects.
We believe this might be due to the changes in:
- https://github.com/dotnet/SqlClient/pull/1785 for 5.0.1 backport
- https://github.com/dotnet/SqlClient/pull/1781 for 5.1.0
With the changes in these PRs, it seems the CancellationToken registration
is not always disposed. There are several if
blocks that may return before the registration
object gets to be saved in the context
. And exceptions could also be thrown.
To reproduce
using Microsoft.Data.SqlClient; // 5.0.1
using System.Threading;
using System.Threading.Tasks;
public static class Program
{
public static async Task Main()
{
const string query = "SELECT 1";
// this could be the application lifetime cancellation
// or another form of global shared cancellation
using var longRunningCts = new CancellationTokenSource();
var connectionString = new SqlConnectionStringBuilder
{
DataSource = "(local)",
IntegratedSecurity = true,
TrustServerCertificate = true,
}.ToString();
try
{
using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(longRunningCts.Token))
using (var connection = new SqlConnection(connectionString))
{
await connection.OpenAsync(linkedCts.Token);
using (var command = new SqlCommand(query, connection))
using (var reader = await command.ExecuteReaderAsync(linkedCts.Token))
{
linkedCts.Cancel();
while (await reader.ReadAsync(linkedCts.Token))
{
}
}
}
}
catch (Exception e)
{
}
// => attach a debugger here
// linkedCts as well as all the SQL objects have been disposed above
// however a memory snapshot shows that the CancellationTokenSource+Registrations and CancellationTokenSource+CallbackNode are still there, including the objects they reference
// so garbage collection cannot happen correctly
}
}
Expected behavior
No memory leak, CancellationTokenSource+CallbackNode entries are not present in a dump.
Further technical details
Microsoft.Data.SqlClient version: 5.0.1 .NET target: .NET 6.0.3 SQL Server version: SQL Server 2019 Operating system: Windows 2019
Additional context
Issue Analytics
- State:
- Created a year ago
- Reactions:17
- Comments:34 (15 by maintainers)
Top Results From Across the Web
c# - Why is my async/await with CancellationTokenSource ...
According to the profiler, those RestResponse objects are being kept alive because they're referred to by the TaskCompletionSource (via the ...
Read more >1784707 – [Regression] [Memory leak] Has unclosed fd
This is expected and a bug in nmstate. Hold on why: When you create an NMClient instance (from after calling either g_initiable_init() or ......
Read more >How to Avoid Data Leakage When Performing Data ...
A careful application of data preparation techniques is required in order to avoid data leakage, and this varies depending on the model ...
Read more >How To Avoid Memory Leaks In JavaScript
In this article, we look at what memory leaks are, their causes, and how to avoid memory leaks in JavaScript.
Read more >Data Leakage And Its Effect On The Performance of An ML ...
Data Leakage is the scenario where the Machine Learning Model is already aware of some part of test data after training.This causes the...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
I think many out there (like me) who took way too long to discover this as the root cause are going to really appreciate upgrading to 5.1.0 when it is released.
I’m having this issue also. After moving to 5.0.1 my Linux server would leak memory rapidly until crashing. Analyzing a memory dump revealed millions of instances of SqlCommand rooted only by the cancellation token registration (CallbackNode). Even after just a couple hours, I can confirm that reverting to 5.0.0 has solved the problem. For an in-depth analysis, including dump screen shots, system configuration, and other information, please see this issue:
(Azure App Service - Linux - Memory Working Set - last 30 days)
(Azure App Service - Linux - Memory Working Set - last 3 days)
I recommend marking 5.0.1 as unstable on NuGet for three reasons: