简体   繁体   中英

C# - Garbage Collection

Ok so I understand about the stack and the heap (values live on the Stack, references on the Heap).

When I declare a new instance of a Class, this lives on the heap, with a reference to this point in memory on the stack. I also know that C# does it's own Garbage Collection (ie. It determines when an instanciated class is no longer in use and reclaims the memory).

I have 2 questions:

  1. Is my understanding of Garbage Collection correct?
  2. Can I do my own? If so is there any real benefit to doing this myself or should I just leave it.

I ask because I have a method in a For loop. Every time I go through a loop, I create a new instance of my Class. In my head I visualise all of these classes lying around in a heap, not doing anything but taking up memory and I want to get rid of them as quickly as I can to keep things neat and tidy!

Am I understanding this correctly or am I missing something?

Ok so I understand about the stack and the heap (values live on the Stack, references on the Heap

I don't think you understand about the stack and the heap. If values live on the stack then where does an array of integers live? Integers are values. Are you telling me that an array of integers keeps its integers on the stack? When you return an array of integers from a method, say, with ten thousand integers in it, are you telling me that those ten thousand integers are copied onto the stack?

Values live on the stack when they live on the stack, and live on the heap when they live on the heap. The idea that the type of a thing has to do with the lifetime of its storage is nonsense. Storage locations that are short lived go on the stack; storage locations that are long lived go on the heap, and that is independent of their type. A long-lived int has to go on the heap, same as a long-lived instance of a class.

When I declare a new instance of a Class, this lives on the heap, with a reference to this point in memory on the stack.

Why does the reference have to go on the stack? Again, the lifetime of the storage of the reference has nothing to do with its type . If the storage of the reference is long-lived then the reference goes on the heap.

I also know that C# does it's own Garbage Collection (ie. It determines when an instanciated class is no longer in use and reclaims the memory).

The C# language does not do so; the CLR does so.

Is my understanding of Garbage Collection correct?

You seem to believe a lot of lies about the stack and the heap, so odds are good no, it's not.

Can I do my own?

Not in C#, no.

I ask because I have a method in a For loop. Every time I go through a loop, I create a new instance of my Class. In my head I visualise all of these classes lying around in a heap, not doing anything but taking up memory and I want to get rid of them as quickly as I can to keep things neat and tidy!

The whole point of garbage collection is to free you from worrying about tidying up. That's why its called "automatic garbage collection". It tidies for you.

If you are worried that your loops are creating collection pressure , and you wish to avoid collection pressure for performance reasons then I advise that you pursue a pooling strategy. It would be wise to start with an explicit pooling strategy; that is:

while(whatever)
{
    Frob f = FrobPool.FetchFromPool();
    f.Blah();
    FrobPool.ReturnToPool(f);
}

rather than attempting to do automatic pooling using a resurrecting finalizer. I advise against both finalizers and object resurrection in general unless you are an expert on finalization semantics.

The pool of course allocates a new Frob if there is not one in the pool. If there is one in the pool, then it hands it out and removes it from the pool until it is put back in. (If you forget to put a Frob back in the pool, the GC will get to it eventually.) By pursuing a pooling strategy you cause the GC to eventually move all the Frobs to the generation 2 heap, instead of creating lots of collection pressure in the generation 0 heap. The collection pressure then disappears because no new Frobs are allocated. If something else is producing collection pressure, the Frobs are all safely in the gen 2 heap where they are rarely visited.

This of course is the exact opposite of the strategy you described; the whole point of the pooling strategy is to cause objects to hang around forever . Objects hanging around forever is a good thing if you're going to use them.

Of course, do not make these sorts of changes before you know via profiling that you have a performance problem due to collection pressure! It is rare to have such a problem on the desktop CLR; it is rather more common on the compact CLR.

More generally, if you are the kind of person who feels uncomfortable having a memory manager clean up for you on its schedule, then C# is not the right language for you. Consider C instead.

values live on the Stack, references on the Heap

This is an implementation detail . There is nothing to stop a .NET Framework from storing both on the stack.

I also know that C# does it's own Garbage Collection

C# has nothing to do with this. This is a service provided by the CLR. VB.NET, F#, etc all still have garbage collection.

The CLR will remove an object from memory if it has no strong roots. For example, when your class instance goes out of scope in your for loop. There will be a few lying around, but they will get collected eventually, either by garbage collection or the program terminating.

Can I do my own? If so is there any real benefit to doing this myself or should I just leave it?

You can use GC.Collect to force a collection. You should not do it because it is an expensive operation. More expensive than letting a few objects occupy memory a little bit longer than they are absolutely needed. The GC is incredibly good at what it does on its own. You will also force short lived objects to promote to generations they wouldn't get normally.

First off, to Erics seminal post about The truth about value types

Secondly on Garbage collection, the collector knows far more about your running program than you do, don't try to second guess it unless you're in the incredibly unlikely situation that you have a memory leak.

So to your second question, no don't try to "help" the GC.

I'll find a post to this effect on the CG and update this answer.

Can I do my own? If so is there any real benefit to doing this myself or should I just leave it.

Yes you can with GC.Collect but you shouldn't . The GC is optimized for variables that are short lived, ones in a method, and variables that are long lived, ones that generally stick around for the life time of the application.

Variables that are in-between aren't as common and aren't really optimum for the GC.

By forcing a GC.Collect you're more likely to cause variables in scope to be in forced into that in-between state which is the opposite from you are trying to accomplish.

Also from the MSDN article Writing High-Performance Managed Applications : A Primer

The GC is self-tuning and will adjust itself according to applications memory requirements. In most cases programmatically invoking a GC will hinder that tuning. "Helping" the GC by calling GC.Collect will more than likely not improve your applications performance

Your understanding of Garbage Collection is good enough. Essentially, an unreferenced instance is deemed as being out-of-scope and no longer needed. Having determined this, the collector will remove an unreferenced object at some future point.

There's no way to force the Garbage Collector to collect just a specific instance. You can ask it to do its normal "collect everything possible" operation GC.Collect() , but you shouldn't.; the garbage-collector is efficient and effective if you just leave it to its own devices.

In particular it excels at collecting objects which have a short lifespan, just like those that are created as temporary objects. You shouldn't have to worry about creating loads of objects in a loop, unless they have a long lifespan that prevents immediate collection.

Please see this related question with regard to the Stack and Heap.

In your specific scenario, agreed, if you new up objects in a for-loop then you're going to have sub-optimal performance. Are the objects stored (or otherwise used) within the loop, or are they discarded? If the latter, can you optimize this by newing up one object outside the loop and re-using it?

With regard to can you implement your own GC, there is no explicit delete keyword in C#, you have to leave it to the CLR. You can however give it hints such as when to collect, or what to ignore during collection, however I'd leave that unless absolutely necessary.

Best regards,

Read the following article by Microsoft to get a level of knowledge about Garbage Collection in C#. I'm sure it'll help anyone who need information regarding this matter.

Memory Management and Garbage Collection in the .NET Framework

If you are interested in performance of some areas in your code when writing C#, you can write unsafe code . You will have a plus of performance, and also, in your fixed block, the garbage collector most likely will not occur.

Garbage collection is basically reference tracking. I can't think of any good reason why you would want to change it. Are you having some sort of problem where you find that memory isn't being freed? Or maybe you are looking for the dispose pattern

Edit: Replaced "reference counting" with "reference tracking" to not be confused with the Increment/Decrement Counter on object Reference/Dereference (eg from Python). I thought it was pretty common to refer to the object graph generation as "Counting" like in this answer: Why no Reference Counting + Garbage Collection in C#? But I will not pick up the glove of (the) Eric Lippert :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM