Memory release with IDisposable and without IDispo

2019-05-17 08:42发布

问题:

In my app I have a large object that created every few seconds I do with it some job and then I dont need it anymore.

I saw in the task manager that the ram size go up even if I dont have ant reference to the object and it will need to being collected.

I tried to implement IDisposable and then the ram goes down immideitly.

Why is this? I dont did GC.Collect I just release the object and tell to GC that he dont need to call finalizer for my object?

Update

Here is the code I use in my IDIsposable objects:

public void Dispose()
{
  base.Dispose();
  Dispoe(true);
  GC.SuppressFinalize();
}

private void Dispoe(bool disposing)
{
  //here i release unmanaged resources
  if (disposing)
  {
    //here i release all managed resources
  }
}

~MyObject()
{
  Dispose(false);
}

And in my large object I do myObject.Dispose(); after i didnt need him anymore.

My question was not about how to implement IDisposable and not about GC generations work at general.

I just want to know how it is possible the case of difference in the ram size between the case i do Dispoe to my object to case that i dont Dispoe my object.

回答1:

As @Steven pointed out in his comments, IDisposable is something the CLR doesn't care about. By implementing it you simply tell consumers of your object to call its Dispose method when object no longer needed. In terms of mem management you can make up your own interface for this, say IDisposable2, and get the same technical effect. This would however be a stupid thing to do because .net developers should know to call idisposable.dispose when object no longer needed. Also, there is built in language (c#) support for this interface (using {...}).

You write "I tried to implement IDisposable and then the ram goes down immideitly."

What matters is what your "implement" does. The code there should clean up unmanaged code, windows resources etc.



回答2:

With .NET memory doesn't have 2 states as usual (used and unused), but in effect 4: (A) Used by live object, (B) Used by dead object, (C) Not used by any object, but by the framework and (D) not used.

When you create an object, the Framework will first try to use memory of category (C) for it, is there isn't enough usable left of it, it will ask the OS for some of type (D), will convert it into (C) and then use it for your object.

When an object goes out of scope, it will fall from (A) to (B), on the next garbage run it will go from (B) to either (C) or (D). This depends heavily on the internal structures (think memeory fragmentation and friends), of the memory pressure and of the type of object collected (think IDisposable and friends)

What you want to achieve is, that as fast as possible after your big Object goes out of scope, the memory it used goes to (D). Here are some hints:

  • Make sure your object's size is a multiple of 4K - this makes it much more likely, that no other object shares a memory page with your object, so it can more easily be given back to the OS

  • Experiment with a AddMemoryPressure() bracket around object disposal, but be aware of side effects. This is similar to forcing GC.Collect(), but less intrusive: It will hint the GC to collect soon, but not exactly now

  • Rethink your basic concept: Is the big object a Singleton (i.e. only one can exist at any given time)? If yes, think of allocating it once and recycling it: This will make your Applications RAM requirements more predictable - and possible save you from ugly OOM situations while running.



回答3:

Using IDisposable means that you are implementing Dispose method where you put all your clean up code for the resources that you dont need anymore. It does not remove your object to the managed heap, the GC will still be the one responsible for freeing up the memory.



回答4:

When you implement IDisposable, and dispose the object, you are marking the object as available to be garbage-collected.

You can't predict exactly when it will be collected though.