1

I can't free proc memory used by my EF DbContext. In spite of dispose and GC.Collect, my application don't free memory.

I created a little program :

static void Main(string[] args) { var test = new TestDb(); System.Threading.Thread.Sleep(1000); // Here proc memory = 7 Mo test.Fill(); System.Threading.Thread.Sleep(1000); // Here proc memory = 58 Mo test.Dispose(); System.Threading.Thread.Sleep(1000); // Here proc memory = 37.8 Mo test = null; GC.Collect(); // Here proc memory = 37.8 Mo // Why is not 0 here ??? System.Threading.Thread.Sleep(1000); } 

You can show memory usage with my comments.

TestDb Class :

 public class TestDb : IDisposable { private List<TaskAction> _actions; public void Fill() { using (var entities = new myEntities()) { entities.Configuration.LazyLoadingEnabled = false; _actions = entities.TaskActions.ToList(); } } public void Dispose() { _actions = null; GC.Collect(); } } 

How can I free all used memory ??

Thanks,

Charly

0

1 Answer 1

3

If we just focus on data memory: the runtime doesn't hand memory back to the OS unless there's a good reason; if you've just been using {some amount of memory}, there's a very good chance you're going to be using that again in a moment, and it is much more efficient to keep hold of it for a while. GC.Collect just deals with internal book keeping so that it doesn't have to ask for more memory from the OS any time soon. There are things you can do to make the runtime more aggressive in returning memory, but... 37Mb is basically nothing.

Additionally, it still takes memory for the internal .NET bits (type metadata, all the assemblies you've loaded, JIT, IL, etc). Doing something, anything with EF (or any other library) is going to tie up some memory in the process that will not be released. And since you've talked to the database, there's also probably now a connection pool (managed and unmanaged), and some SQL-related threads.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks Marc, this is very helpful. However, what if there are particular requests that consumes large amounts of memory? In my case, creating an Excel file with EFCore data. The constructed file (in memory) is quite large. I would like to force .net to NOT cache that memory. I tried GC.Collect but that didn't work. I've resorted to using <ServerGarbageCollection>false</ServerGarbageCollection>.
@Sean define "cache" in that sentence; .net doesn't have some magic cache API; if an object is reachable, then it isn't collectable, so if what you're saying is you want objects to be collectable sooner: then they need to not be reachable; without looking at your model in great detail, that's very hard to discuss; you could try disabling tracking, and get rid of the db context (i.e. make sure it isn't reachable), but: anything more than that: needs detailed context, that I don't have
(This is probably not the place for this discussion, but...) Cache might have been the wrong word; I was referring to your mentioning that it stores items in memory in case it might be used again in a moment. I can see on my dev machine that this particular request raises memory by about 500MB, and that doesn't get released quickly. Most of that is most likely building an XLSX doc in memory with EPPlus. The EPPlus reference and the DBContext (+loaded data) should get disposed after the request, but one or both are presumably sticking around. Tracking is disabled as it is all read-only access.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.