-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Excessive memory usage after enabling DbContextFactory #28988
Comments
Yeah, thanks for flagging this. We reuse the same RelationalDataReader instance across RelationalCommand invocations, since EF 6.0 (part of the query optimizations). RelationalDataReader maintains a reference to its DbDataReader, which is provided each time Initialize is called; but that reference is only removed when the same instance of RelationalDataReader is reused for another query. This isn't a problem for e.g. SqlDataReader, but it's a problem for BufferedDataReader. And since RelationalDataReader is cached all the way to the RelationalConnection, we potentially have 1024 pooled contexts, each with its own RelationalDataReader referencing a BufferedDataReader. We should clear out the reference to the DbDataReader when RelationalDataReader is disposed. |
I'm wondering about the disposal of _currentResultSet i BufferedDataReader. The memory dump show that the memory is referenced in _currentResultSet and this is not disposed/cleared when BufferedDataReader is Closed / Disposed: BufferedDataReader.cs:
Shouldn't _currentResultSet variable also be disposed/set to null? |
My approach in #28989 was simply to sever the reference from RelationalDataReader (which is recycled and therefore referenced from pooled DbContext instances) to DbDataReader. Unless I'm missing something, that means that BufferedDataReader and all of its referenced data (including _currentResultSet) should become eligible for garbage collection once the query's enumerator is disposed. |
Yes, that will work for PooledDbContext but if you have a long living DbContext the _currentResultSet variable will not be cleared until the next query is executed. Maybe no problem. |
Why is that? Context pooling shouldn't be relevant here; the moment a query enumerator is disposed (the query finishes evaluating), RelationalDataReader.Dispose() is called, and #28989 that sets RelationalDataReader._reader to null. At this point there should be no more references to the BufferedDataReader and the GC can reclaim it. Or are you seeing something different in the code? |
No, my mistake from not being so familiar with the internals of EF Core. |
No problem, it's great to have another pair of eyes on this. |
Reopening to consider for servicing. |
Fixes dotnet#28988 (cherry picked from commit 4bb67a7)
Fixes dotnet#28988 (cherry picked from commit 4bb67a7)
@jonnybee I've merged #28989 for 7.0 and submitted #29005 for considering for 6.0. Can you please try out the latest 7.0 daily build and confirm that it fixes the issue for you? |
You shouldn't need to build yourself, rather just use the daily build feed.
Thanks! we'll look into this. |
I verified the fix from the daily build feed but tried to test changes in Clear method in StateManager by creating a private build and that failed on assembly load at runtime in my test program. |
@jonnybee can you please open a new issue for the above so we can track it separately from the original issue? |
Using EF Core 6.0.5 and Microsoft.Data.SqlClient 4.1.0 running in Azure AppService and SqlAzure database.
After enabling DbContextFactory we se excessive memory usage in our application.
The context pool is as default (up to 1024 DbContexts) and there is a number of VARCHAR(MAX) columns in our database.
When a DbContext is return to pool the SqlConnection (and BufferedDataReader) will still hold a large amount of memory from the last SQL Query.
Am I doing something wrong or shouldn't this be cleared from the pooled DbContext?
The text was updated successfully, but these errors were encountered: