-
Notifications
You must be signed in to change notification settings - Fork 314
Closed
Labels
Regression 💥Issues that are regressions introduced from earlier PRs.Issues that are regressions introduced from earlier PRs.
Description
Describe 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:
- [Release 5.0] Fixes ReadAsync() behavior to register Cancellation token action before streaming results #1785 for 5.0.1 backport
- Fixes ReadAsync() behavior to register Cancellation token action before streaming results #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
Chocanto, bryanwieg, miguelelvir, jeffpardy, oatkins and 14 more
Metadata
Metadata
Assignees
Labels
Regression 💥Issues that are regressions introduced from earlier PRs.Issues that are regressions introduced from earlier PRs.