-
Notifications
You must be signed in to change notification settings - Fork 299
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Memory leak when an exception is raised during execution of SqlCommand with CancellationToken #1682
Comments
There is no (4.8.3) version of Microsoft.Data.SqlClient. are you testing against the deprecated System.Data.SqlClient ? |
I've corrected SqlClient version. It is version 4.1.0 of Microsoft.Data.SqlClient. |
On first glance, it looks like you just need to add Because if BeginExecuteNonQueryAsync throws an exception, ContinueWith (which calls registration.Dispose()) will not be called. |
Same with InternalExecuteReaderAsync, seems like registration.Dispose() is missed in catch block: |
@olegkv Thanks for the Repro, I can see the memory usage going quickly over a GB with tokens option whereas without token it remains under 100 MB even running for few minutes. The behavior is same for System.Data.SqlClient and earlier version of Microsoft.Data.SqlClient 3.1.0 as well. I will investigate further to find the cause. |
This looks like the probable fix but there is a complication that we must make sure we don't double dispose the registration variable. The registration itself does not report whether it has been disposed so we will need to carry and check that state along with the registration. |
@olegkv can you verify if the same behaviour occurs with ExecuteReader? And would you be willing to try some dev builds if I open a PR to address this? There is a way to eliminate quite a few allocations in ExecuteNonQuery that I hadn't got around to doing yet because I'm waiting on source merges between netcore/netfx but it would be good to check if the rewrite I have planned fixes the problem. |
@Wraith2 Yes, same issue happens with ExecuteReaderAsync too. That matches with source code for InternalExecuteReaderAsync missing registration.Dispose() call. Also, you said: But MS documentation explicitly says that components must allow multiple Dispose calls: |
@Wraith2 Yes, sure I can try some dev builds. Anyone can try it easily, just copy the code from original post above and run it, comment and uncomment calls with token and without token and see the difference. |
Description
When using CancellationToken, an exception raised by sqlCommand.ExecuteNonQueryAsync() causes memory leaks.
When not using CancellationToken, an exception raised by sqlCommand.ExecuteNonQueryAsync() does not cause any memory leaks.
More details about context
When we run a background process which executes sql commands in regular (scheduled) manner (execute-sleep-execute), and using global CancellationToken, process would go out of memory if some commands generate errors.
To reproduce
Run the code below. Comment and uncomment calls of ExecuteNonQueryAsync to see the difference between using CancellationToken and not using it.
Expected behavior
When using CancellationToken, memory usage should be the same as in the case of not using CancellationToken
Further technical details
Microsoft.Data.SqlClient version: (4.1.0)
.NET target: (Net 5 and 6)
Operating system: (Windows)
The text was updated successfully, but these errors were encountered: