-
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
QueryCache: Memory leak when using dbContext.Set<> in subquery #8063
Comments
Note for triage: The call to Set is returning a new DbSet instance each time it is called. Probably needs special handling in the cache. |
Verified fixed in 2.0 |
@anpete does it exist any workaround that I can do in my solution? I have multiple ecommerce applications that need to be restarted on a regular schedule. |
I can see that this is partial fixed in branch |
@Tasteful Is it possible for you to use DbSet properties on your context? |
@ajcvickers No, it is not possible. We register everything dynamic in |
@Tasteful How about something like this: public class DbSets
{
private readonly DbContext _context;
public DbSets(DbContext context)
{
_context = context;
}
private readonly IDictionary<Type, object> _sets
= new Dictionary<Type, object>();
public DbSet<TEntity> Set<TEntity>() where TEntity : class
{
object set;
if (!_sets.TryGetValue(typeof(TEntity), out set))
{
set = _context.Set<TEntity>();
_sets.Add(typeof(TEntity), set);
}
return (DbSet<TEntity>)set;
}
} Then in your context: public class MyTestContext : DbContext
{
private readonly DbSets _sets;
public MyTestContext(DbContextOptions options)
: base(options)
{
_sets = new DbSets(this);
}
public DbSet<TEntity> CachedSet<TEntity>() where TEntity : class
=> _sets.Set<TEntity>();
} Then use CachedSet in your queries instead of Set. I tested this with your repro code and I see it caching correctly. |
@Tasteful Agree we should consider this for the next patch. A possible workaround might be to register a custom IQueryCompiler so you can apply the fix yourself. I think the high-level approach would be:
|
@ajcvickers If I understand it correctly the problem is that the @anpete I can try this suggestion also, but in general I'm against to use the classes/methods in the internal namespace due to possible conflicts between versions. |
@ajcvickers One strange thing is that if I add an override in my dbcontext as below, then the cache will still not work correctly, but if I set it as CaachedSet, then the cache will work. Should it not work with the override like this?
|
@Tasteful Based on my understanding overriding Set like that should work. You shouldn't need the Concurrent Dictionary though because context instances are not thread-safe. |
If I add an interface as below on the my dbcontext implementation and cast the dbcontext into that interface during query the cache will work without doing anything else.
|
@Tasteful Seems my theory for the bug was off a bit. Glad you found a workaround; we will still discuss if this should go in a patch. |
@ajcvickers I was wrong. Casting to interface was only changing the query to client evaluation and that was throwing exception and I think that the performance not will be good to fetch everything from db. I added the following into options builder also I will try to fix my own |
@anpete Your solution to override the |
@Tasteful Great to hear. The difficulty extending is an oversight, I will file an issue to fix. |
@ajcvickers Risk is low, I think we should patch it. I see Set being used pretty often in user repositories etc. |
This patch fix is approved. Please follow the normal code review / pull request process and make sure you make the change in the correct branch. |
@anpete Is this merged into the 1.1.2 branch yet? |
@ajcvickers Yep. |
Preview builds of this patch fix should be available on the following feeds:
If you have a chance, please try out these preview builds and let us know if you have any feedback! |
@Tasteful Could you check using the feed above that the fix checked in solves the problem you are seeing. It would be greatly appreciated. |
@ajcvickers I have tested the I noticed that the package |
@Tasteful each "repo" versions independently, so all packages within a repo generally have the same version, though different repos might be on somewhat different versions. Glad you're now seeing the behavior you're expecting! |
Verified fixed in 1.1.2 candidate build. |
When using
dbContext.Set<MyTable1>()
query cache is caching each instance that will fill memory with the same query.The following is the result from https://github.com/Tasteful/bugs/blob/query-cache-memory-leak/MemoryUsage/Program.cs#L29-L56 where the only different is that the first result is using
DbSet<>
and the second usingSet<>
.This issue is probably related to #6737 that have fixes for
DbSet<>
.Steps to reproduce
Full running example exists here https://github.com/Tasteful/bugs/tree/query-cache-memory-leak
Further technical details
EF Core version: 1.1.1
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Operating system: Windows 10
IDE: VS2017
The text was updated successfully, but these errors were encountered: