how garbage collector keeps on tracking roots from stack - c#

void method ()
{
Type obj = new Type () ;
}
maybe i misunderstand something, but when function returns and stack is unwound, 'obj' somehow must be deleted from the root set. how does this mechanism work? I already searched here and googled it, but found nothing to clarify my question.

There is no "subtraction", that would make calling a method entirely too expensive. A primary role here is played by the just-in-time compiler. It does not just translate MSIL to machine code, it also generates a table that describes how objects are used by the method. That table contains the addresses of the code locations where the object is used as well as where it is stored.
Note how the stack is an abstraction, the far more common place where an object reference is stored is in a processor register. The GC needs to know what register is used to properly track object usage. And the stack frame offset if it does get spilled to the stack.
When the garbage collector gets going then it walks the stack, traversing the stack frames of the active methods. And uses the table associated with each method to find the object references back. With the big advantage that nothing special needs to be done when a method completes, the stack frame simply is not there anymore. The table also makes garbage collection very efficient, an object can be collected even when the method has not yet finished executing. Matters a lot for, say, your Main() method, you would not want any object you use in that method to leak for the lifetime of the app. It makes the fixed statement very cheap, the table simply has a bit that says that the object should not be moved.
The existence of that table is the distinction between managed and unmanaged code. More about that table in this answer.

See this article here. http://www.c-sharpcorner.com/uploadfile/riteshratna/garbage-collection-memory-management-in-net/
Check out the section on managed heap through application roots. This list of roots is available to the garbage collector to determine which object can be collected.

Related

Why does this C# code note leak? [duplicate]

Consider the below code:
public class Class1
{
public static int c;
~Class1()
{
c++;
}
}
public class Class2
{
public static void Main()
{
{
var c1=new Class1();
//c1=null; // If this line is not commented out, at the Console.WriteLine call, it prints 1.
}
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine(Class1.c); // prints 0
Console.Read();
}
}
Now, even though the variable c1 in the main method is out of scope and not referenced further by any other object when GC.Collect() is called, why is it not finalized there?
You are being tripped up here and drawing very wrong conclusions because you are using a debugger. You'll need to run your code the way it runs on your user's machine. Switch to the Release build first with Build + Configuration manager, change the "Active solution configuration" combo in the upper left corner to "Release". Next, go into Tools + Options, Debugging, General and untick the "Suppress JIT optimization" option.
Now run your program again and tinker with the source code. Note how the extra braces have no effect at all. And note how setting the variable to null makes no difference at all. It will always print "1". It now works the way you hope and expected it would work.
Which does leave with the task of explaining why it works so differently when you run the Debug build. That requires explaining how the garbage collector discovers local variables and how that's affected by having a debugger present.
First off, the jitter performs two important duties when it compiles the IL for a method into machine code. The first one is very visible in the debugger, you can see the machine code with the Debug + Windows + Disassembly window. The second duty is however completely invisible. It also generates a table that describes how the local variables inside the method body are used. That table has an entry for each method argument and local variable with two addresses. The address where the variable will first store an object reference. And the address of the machine code instruction where that variable is no longer used. Also whether that variable is stored on the stack frame or a cpu register.
This table is essential to the garbage collector, it needs to know where to look for object references when it performs a collection. Pretty easy to do when the reference is part of an object on the GC heap. Definitely not easy to do when the object reference is stored in a CPU register. The table says where to look.
The "no longer used" address in the table is very important. It makes the garbage collector very efficient. It can collect an object reference, even if it is used inside a method and that method hasn't finished executing yet. Which is very common, your Main() method for example will only ever stop executing just before your program terminates. Clearly you would not want any object references used inside that Main() method to live for the duration of the program, that would amount to a leak. The jitter can use the table to discover that such a local variable is no longer useful, depending on how far the program has progressed inside that Main() method before it made a call.
An almost magic method that is related to that table is GC.KeepAlive(). It is a very special method, it doesn't generate any code at all. Its only duty is to modify that table. It extends the lifetime of the local variable, preventing the reference it stores from getting garbage collected. The only time you need to use it is to stop the GC from being to over-eager with collecting a reference, that can happen in interop scenarios where a reference is passed to unmanaged code. The garbage collector cannot see such references being used by such code since it wasn't compiled by the jitter so doesn't have the table that says where to look for the reference. Passing a delegate object to an unmanaged function like EnumWindows() is the boilerplate example of when you need to use GC.KeepAlive().
So, as you can tell from your sample snippet after running it in the Release build, local variables can get collected early, before the method finished executing. Even more powerfully, an object can get collected while one of its methods runs if that method no longer refers to this. There is a problem with that, it is very awkward to debug such a method. Since you may well put the variable in the Watch window or inspect it. And it would disappear while you are debugging if a GC occurs. That would be very unpleasant, so the jitter is aware of there being a debugger attached. It then modifies the table and alters the "last used" address. And changes it from its normal value to the address of the last instruction in the method. Which keeps the variable alive as long as the method hasn't returned. Which allows you to keep watching it until the method returns.
This now also explains what you saw earlier and why you asked the question. It prints "0" because the GC.Collect call cannot collect the reference. The table says that the variable is in use past the GC.Collect() call, all the way up to the end of the method. Forced to say so by having the debugger attached and by running the Debug build.
Setting the variable to null does have an effect now because the GC will inspect the variable and will no longer see a reference. But make sure you don't fall in the trap that many C# programmers have fallen into, actually writing that code was pointless. It makes no difference whatsoever whether or not that statement is present when you run the code in the Release build. In fact, the jitter optimizer will remove that statement since it has no effect whatsoever. So be sure to not write code like that, even though it seemed to have an effect.
One final note about this topic, this is what gets programmers in trouble that write small programs to do something with an Office app. The debugger usually gets them on the Wrong Path, they want the Office program to exit on demand. The appropriate way to do that is by calling GC.Collect(). But they'll discover that it doesn't work when they debug their app, leading them into never-never land by calling Marshal.ReleaseComObject(). Manual memory management, it rarely works properly because they'll easily overlook an invisible interface reference. GC.Collect() actually works, just not when you debug the app.
[ Just wanted to add further on the Internals of Finalization process ]
You create an object and when the object is garbage collected, the object's Finalize method should be called. But there is more to finalization than this very simple assumption.
CONCEPTS:
Objects not implementing Finalize methods: their memory is reclaimed immediately, unless of course, they are not reachable by application code any more.
Objects implementing Finalize method: the concepts of Application Roots, Finalization Queue, Freachable Queue need to be understood since they are involved in the reclamation process.
Any object is considered garbage if it is not reachable by application code.
Assume: classes/objects A, B, D, G, H do not implement the Finalize method and C, E, F, I, J do implement the Finalize method.
When an application creates a new object, the new operator allocates memory from the heap. If the object's type contains a Finalize method, then a pointer to the object is placed on the finalization queue. Therefore pointers to objects C, E, F, I, J get added to the finalization queue.
The finalization queue is an internal data structure controlled by the garbage collector. Each entry in the queue points to an object that should have its Finalize method called before the object's memory can be reclaimed.
The figure below shows a heap containing several objects. Some of these objects are reachable from the application roots, and some are not. When objects C, E, F, I, and J are created, the .NET framework detects that these objects have Finalize methods and pointers to these objects are added to the finalization queue.
When a GC occurs (1st Collection), objects B, E, G, H, I, and J are determined to be garbage. A,C,D,F are still reachable by application code depicted as arrows from the yellow box above.
The garbage collector scans the finalization queue looking for pointers to these objects. When a pointer is found, the pointer is removed from the finalization queue and appended to the freachable queue ("F-reachable", i.e. finalizer reachable). The freachable queue is another internal data structure controlled by the garbage collector. Each pointer in the freachable queue identifies an object that is ready to have its Finalize method called.
After the 1st GC, the managed heap looks something similar to figure below. Explanation given below:
The memory occupied by objects B, G, and H has been reclaimed immediately because these objects did not have a finalize method that needed to be called.
However, the memory occupied by objects E, I, and J could not be reclaimed because their Finalize method has not been called yet. Calling the Finalize method is done by freachable queue.
A, C, D, F are still reachable by application code depicted as arrows from yellow box above, so they will not be collected in any case.
There is a special runtime thread dedicated to calling Finalize methods. When the freachable queue is empty (which is usually the case), this thread sleeps. But when entries appear, this thread wakes, removes each entry from the queue, and calls each object's Finalize method. The garbage collector compacts the reclaimable memory and the special runtime thread empties the freachable queue, executing each object's Finalize method. So here finally is when your Finalize method gets executed.
The next time the garbage collector is invoked (2nd GC), it sees that the finalized objects are truly garbage, since the application's roots don't point to it and the freachable queue no longer points to it (it's EMPTY too), therefore the memory for the objects E, I, J may be reclaimed from the heap. See figure below and compare it with figure just above.
The important thing to understand here is that two GCs are required to reclaim memory used by objects that require finalization. In reality, more than two collections cab be even required since these objects may get promoted to an older generation.
NOTE: The freachable queue is considered to be a root just like global and static variables are roots. Therefore, if an object is on the freachable queue, then the object is reachable and is not garbage.
As a last note, remember that debugging application is one thing, garbage collection is another thing and works differently. So far you can't feel garbage collection just by debugging applications. If you wish to further investigate memory get started here.

Minimizing usage of RAM by created objects in runtime in C#

I was wondering what are the best practices when creating objects, performing LINQ in C#. For instance, I realize that when I open up a connection using LINQ I should be putting the model object into a using statement like this:
using(var ctx = new mymodel())
{
}
Now, what about the objects that are EF classes?
They do not implement IDisposable interface thus I can't do something like this when creating an object like this for example:
using(var user = new Users())
{
}
But when an action is called like this:
public ActionResult InsertUser()
{
var user = new Users();
}
I have no clear picture what happens with this object once the insert into the db is finished. Does this object stays allocated in memory or it gets released? If not, what are best practices to release memory once they aren't needed anymore..?
On the other there are static variables as well...
So to sum things up, my questions are:
what are best practices to release memory when creating instances of an object of a class?
Is implementation of IDisposable interface on every class that I have good choice?
When a static variable is created in .NET MVC, what is the best way to release memory taken by this kind of variables?
Same question goes for Session object?
P.S. Guys, I'd really appreciate if all of you that are reading this to post your opinion or post some useful links for some documentations/blog posts so that I can expand my horizons =)
Before you do any performance tweaks I highly recommend to run a memory profiler (for example JetBrains dotMemory, but there are others) and find out the actual source of the problem. Without information from profiler, your optimisations will be like sticking your finger at a sky and shouting "Rainbow!" i.e. useless at best, harmful at worst.
Also after identifying issues with profiler, but before starting changing your code, I recommend reading about how Garbage Collection works in .Net. Here are some references to get you started:
MSDN Garbage Collection
MSDN Garbage Collector Basics and Performance Hints
.Net Garbage Collection in depth
Here are some links to answer your questions:
IDisposable vs Garbage Collector
Static vs Garbage Collector: 1, 2
Session and Garbage Collection
In response to comment.
When you create regular .NET object, .NET runtime knows everything about it, because runtime created it. It knows where in memory it's located, when it is no longer needed and so on. When it is no longer needed - runtime will reclaim its memory. That is managed (by runtime) object. You should not care about memory management for such objects.
Now take for example file handle. When you open file in .NET, it will delegate this operation to OS (for example, Windows). This resource is not managed by runtime, it is managed by OS. So, it is unmanaged resource. So author of .NET library code which works with files (I mean person who created FileStream and similar classes, not uses them) should manually write code to release such resource (close file handle in this case). By convention, author will use IDisposable.Dispose method for code that releases such resources AND ensures that when underlying object (like FileStream) will be collected by GC - unmanaged resources will also be released. So even if you forget to call Dispose - file handle will be closed when GC collects FileStream (not that it will happen not magically but because code author explicitly made it happen like this). But that might happen any time in the future, you don't want to leave file handle open for undetermined time - so you always call Dispose yourself when you are done with IDisposable object.
The same applies to most unmanaged resources. For example, database connection is managed by database, and you don't want to leave database connection open for undetermined time, so you call Dispose and explicitly notify database to close it (and even if you don't call it - author of .NET database code took care to do that when object is collected). EF context wraps database connection, so it also implements IDisposable. If you don't want to leave connection open until context will be collected (and you sure don't want that) - you call Dispose yourself.
Or suppose you write your own code to work with images using ImageMagick. That is C library, so runtime has no idea about its inner workings. You ask library to allocate memory for your image, but .NET cannot reclaim such memory - it does not manage it, it is managed by ImageMagick C library. So you implement IDisposable and tell ImageMagick to release memory in that method.
In the case of var user = new Users(); which does not implement IDisposable, and any object for that matter which is not disposed, will only be guaranteed to exist where there is an active reference to this object; after which it will qualify for disposal the next time the Garbage Collector (GC) tries to free up memory.
In your example above, as soon as this leaves the method InsertUser() it will no longer have any references pointing to it, and therefore will be up for garbage collection.
If however a reference exists, such as in the following code, the object will not be disposed until the reference is cleared, or the containing class is disposed.
private User _insertedUser;
public ActionResult InsertUser()
{
_insertedUser = new Users();
}
The garbage collector fires when the application needs to release some memory. When it fires, it performs several sweeps on objects within memory to tell if any references exist. It first scans every object which has been newly created since the last time the GC was called. Objects which survive this sweep are promoted a generation. If after the sweep more memory is still required, then a 2nd generation sweep is performed. This will scan every object which has survived a single garbage collection to see if it can now be freed. Again if an object survives, it moves up another generation, with 3 generation sweeps in total.
This method helps the GC perform memory management while limiting the high costs involved (newer objects are more likely to be available for release). As GC has a high cost associated to it, it's better if objects are disposed of through user's code to help limit the number of times the GC is called.
tldr;
Dispose objects if they implement IDisposable; an easy way is to
surround it by a 'using'.
If an object cannot be disposed, and it is no longer required, make sure all references to the object is cleared (especially references outside of a method which the object was created).
This enables the GC to release it from memory.

Does the Code Block of a method live in the stack or heap at the moment of execution?

I'm relatively new to learning programming languages, and I feel I have 20 to 25% of understanding of Object Oriented Programming Language, more specifically C# language. So I really state this question without knowing the actual significance of its answer, if any, to my process of learning the language, but I really felt I need to ask it.
When a method is called for execution, I know that all its local variables and its parameters and return value are actually present in the stack memory. While the method itself is called from the heap memory as a member of an instantiated object or a static class, or as a static member of a of a non static class.
Now my question here is, when the method is called into the stack, is it only the variables and parameters that are going to exist in the stack, or is it the whole method with all its code block will be existing in the stack at that moment ( of execution )?
This query has arisen from the analogous comparison of nature of the code block inside an instantiated method ( or a static method ), while the method is being called and while it isn't being called, when compared to the nature of the members of a non static class while the class is instantiated into an object, and while not.
Now, the members of a nonstatic class, are thought of like a blue print, i.e. they are existing in a form that is non-approachable and non-functional ( fields and methods cannot be called, and the values of fields cannot get changed, the methods cannot change values ), but this blueprint is rather instantiable into a concrete functioning object with its members.
Now if the code block inside an instantiated method in the heap is nothing but a blueprint, a blueprint that will practically get "instantiated" in the stack when the method is being called, to perform the task their in the stack, then get deleted off the stack when the task is accomplished. Here the stack can be seen as the place of actual execution of the program, while on the other hand everything in the heap including the static classes and the objects and the heap itself will be seen as a mere storage place for data and instructions for the stack to borrow and utilise every now and then, the stack actually performs the tasks of our whole program.
If, however, the stack memory doesn't actually contain the code of a method that is getting executed, and the stack only takes the temporary values of the method's local variables and parameters, while the method itself in the heap and concurrently performing the coded instructions from its heap position, loaning only the values to the stack in the process. Here the stack will look like a mere variable's value holder, while the object and static classes with their methods are the actual performers of the program their in the heap itself, and an instantiated method ( or a static one ) with its code is concretely present and functioning in the heap.
A third possibility is that neither of the two memories ( stack and heap ) are the actual place of code execution, rather somewhere in the processor itself that the execution and changing of data is taking place, with both the heap and stack being mere storage places for different patterns of utilisation in terms of accepting, preserving, and cleaning data and instructions, and that's it.
I'm sorry for such a long question, I don't know how helpful to gain its answer for me as a programmer, but it really caused me a headache for couple of days and I couldn't find an answer in the text that are designed for beginners so I got really overwhelmed!
Methods are not instantiated. Classes are instantiated in order to create objects.
Objects consist of data members and methods. Only the data members are allocated either somewhere in the process'es memory dynamically. The code of all methods is statically located in a section of memory called 'code segment'. No code of any method is ever copied. It is not needed since it's perfectly constant.
Stack has nothing to do with code. Only local variables and parameters live on the stack. Note that if the type of the variable / parameter is a reference, then just the value of the reference (pointer) lives on the stack, but the actual object it's pointing to is located somewhere else.
An article providing an introduction into .NET's memory management basics can be found here.
Note: This is a little bit simplifying view, but accurate for your level of knowledge.
The program code is in the program's code region. It's in neither the heap nor the stack. It's in a region of memory set up by the loader when the program is executed.
I suggest you read more about program linking and loading.

Do references get updated when Garbage Collectors move data in heap?

I read that GC (Garbage Collectors) moves data in Heap for performance reasons, which I don't quite understand why since it is random access memory, maybe for better sequential access but I wonder if references in Stack get updated when such a move occurs in Heap. But maybe the offset address remains the same but other parts of data get moved by Garbage Collectors, I am not sure though.
I think this question pertains to implementation detail since not all garbage collectors may perform such optimization or they may do it but not update references (if it is a common practice among garbage collector implementations). But I would like to get some overall answer specific to CLR (Common Language Runtime) garbage collectors though.
And also I was reading Eric Lippert's "References are not addresses" article here, and the following paragraph confused me little bit:
If you think of a reference is actually being an opaque GC handle then
it becomes clear that to find the address associated with the handle
you have to somehow "fix" the object. You have to tell the GC "until
further notice, the object with this handle must not be moved in
memory, because someone might have an interior pointer to it". (There
are various ways to do that which are beyond the scope of this
screed.)
It sounds like for reference types, we don't want data to be moved. Then what else we store in the heap, which we can move around for performance optimization? Maybe type information we store there? By the way, in case you wonder what that article is about, then Eric Lippert is comparing references to pointers little bit and try to explain how it may be wrong to say that references are just addresses even though it is how C# implements it.
And also, if any of my assumptions above is wrong, please correct me.
Yes, references get updated during a garbage collection. Necessarily so, objects are moved when the heap is compacted. Compacting serves two major purposes:
it makes programs more efficient by using the processor's data caches more efficiently. That is a very, very big deal on modern processors, RAM is exceedingly slow compared to the execution engine, a fat two orders of magnitude. The processor can be stalled for hundreds of instructions when it has to wait for RAM to supply a variable value.
it solves the fragmentation problem that heaps suffer from. Fragmentation occurs when a small object is released that is surrounded by live objects. A hole that cannot be used for anything else but an object of equal or smaller size. Bad for memory usage efficiency and processor efficiency. Note how the LOH, the Large Object Heap in .NET, does not get compacted and therefore suffers from this fragmentation problem. Many questions about that at SO.
In spite of Eric's didactic, an object reference really is just an address. A pointer, exactly the same kind you'd use in a C or C++ program. Very efficient, necessarily so. And all the GC has to do after moving an object is update the address stored in that pointer to the moved object. The CLR also permits allocating handles to objects, extra references. Exposed as the GCHandle type in .NET, but only necessary if the GC needs help determining if an object should stay alive or should not be moved. Only relevant if you interop with unmanaged code.
What is not so simple is finding that pointer back. The CLR is heavily invested in ensuring that can be done reliably and efficiently. Such pointers can be stored in many different places. The easier ones to find back are object references stored in a field of an object, a static variable or a GCHandle. The hard ones are pointers stored on the processor stack or a CPU register. Happens for method arguments and local variables for example.
One guarantee that the CLR needs to provide to make that happen is that the GC can always reliably walk the stack of a thread. So it can find local variables back that are stored in a stack frame. Then it needs to know where to look in such a stack frame, that's the job of the JIT compiler. When it compiles a method, it doesn't just generate the machine code for the method, it also builds a table that describes where those pointers are stored. You'll find more details about that in this post.
Looking at C++\CLI In Action, there's a section about interior pointers vs pinning pointers:
C++/CLI provides two kinds of pointers that work around this problem.
The first kind is called an interior pointer, which is updated by the
runtime to reflect the new location of the object that's pointed to
every time the object is relocated. The physical address pointed to by
the interior pointer never remains the same, but it always points to
the same object. The other kind is called a pinning pointer, which
prevents the GC from relocating the object; in other words, it pins
the object to a specific physical location in the CLR heap. With some
restrictions, conversions are possible between interior, pinning, and
native pointers.
From that, you can conclude that reference types do move in the heap and their addresses do change. After the Mark and Sweep phase, the objects get compacted inside the heap, thus actually moving to new addresses. The CLR is responsible to keep track of the actual storage location and update those interior pointers using an internal table, making sure that when accessed, it still points to the valid location of the object.
There's an example taken from here:
ref struct CData
{
int age;
};
int main()
{
for(int i=0; i<100000; i++) // ((1))
gcnew CData();
CData^ d = gcnew CData();
d->age = 100;
interior_ptr<int> pint = &d->age; // ((2))
printf("%p %d\r\n",pint,*pint);
for(int i=0; i<100000; i++) // ((3))
gcnew CData();
printf("%p %d\r\n",pint,*pint); // ((4))
return 0;
}
Which is explained:
In the sample code, you create 100,000 orphan CData objects ((1)) so
that you can fill up a good portion of the CLR heap. You then create a
CData object that's stored in a variable and ((2)) an interior pointer
to the int member age of this CData object. You then print out the
pointer address as well as the int value that is pointed to. Now,
((3)) you create another 100,000 orphan CData objects; somewhere along
the line, a garbage-collection cycle occurs (the orphan objects
created earlier ((1)) get collected because they aren't referenced
anywhere). Note that you don't use a GC::Collect call because that's
not guaranteed to force a garbage-collection cycle. As you've already
seen in the discussion of the garbage-collection algorithm in the
previous chapter, the GC frees up space by removing the orphan objects
so that it can do further allocations. At the end of the code (by
which time a garbage collection has occurred), you again ((4)) print
out the pointer address and the value of age. This is the output I got
on my machine (note that the addresses will vary from machine to
machine, so your output values won't be the same):
012CB4C8 100
012A13D0 100

Does Garbage Collection ever affect stack?

I have just started with .NET Framework with C# as my language. I somewhat understand the concept of GC in Java, and had a revisit to the same concept in .NET today.
In C#, the value types are put onto the stack(same as the case with Java,where local variables are put onto the stack). But in C#, even struct is included in value types. So, even structs are placed onto the stack. In a worst case scenario, where there are many method calls, and the stack is populated heavily with many methods, and each method has many local value types, and many structs that themselves have many local value types, will the Garbage Collector ever affect the stack? From what I researched(and partly what I was taught about), I understand that it won't do so. Primarily because manipulating stack content will involve a lot of overhead, and besides, GC only consults stack to lookup for references - and nothing more than that.
Just to add another question related on the same topic : Forcing a call to GC(like System.gc() in Java, not sure about the C# equivalent), doesn't ensure that the GC routine is called then and there. So where should I place such a call - where I expect that I need the GC to run, or any random place as there is no guarantee that my call would immediately trigger the GC? Or should I just leave the stuff to the Runtime Environment and not bother about it?
Note: I added the Java tag because I'm trying to link concepts from there. I understand that the internal functioning of GC in the two separate Runtime Environments will definitely be different, but I guess the underlying concept would be the same.
No garbage collect does not affect objects on the java stack.
GC only affects objects in the jvm's heap. The java GC process is multi-tiered and can be very complex, and worth reading up on. Check out a site like: http://javarevisited.blogspot.com/2011/04/garbage-collection-in-java.html to get a good grasp on how it operates.
As far as forcing the system's GC that is a bad idea. The jvm will have a better idea that you when a GC needs to run. If you are attempting to allocate a big object, the jvm will ensure the space is there for you without you needing to tell it to run the GC.
EDIT
My bad, you are more concerned about C# than java. The same principals of memory management apply, stack is unaffected, don't explicitly run a GC, etc. C# is designed to operate in a similar manor to java. http://msdn.microsoft.com/en-us/library/ms973837.aspx
Stacks don't need the assistance of a garbage collector; because, as you move out of stack frames (the scope of the current execution within the stack), the entire frame, including contents, is freed (and overwritten) as you create a new stack frame.
function foo(int a, int b) {
int i;
doStuff();
}
creates a stack frame (rough visualization)
---- Frame Start ----
(value for parameter a)
(value for parameter b)
(other items needed for tracking execution)
(extra stack frame space
(value for stack allocated i)
)
---- End of Frame ----
When entering a function, stack allocated variables are allocated as the frame is allocated, when exiting the frame, the entire frame is discarded, deallocating the memory for frame allocated variables.
Keep in mind that Java typically allocates object references and stack local primitives on the stack, not whole objects. Only a few recent optimizations permit in-stack allocation of objects not reachable outside the frame; which has such conditions on it that it is not considered something you can count on.
That said, references in the stack frame typically point to the heap, which is garbage collected normally.
If you read this for .NET, it only works on the managed heap:
http://msdn.microsoft.com/en-us/library/ee787088.aspx
MSDN seems to be a treasure trove of information, here is the parent topic on the GC in the CLR:
http://msdn.microsoft.com/en-us/library/0xy59wtx
.NET garbage collection is explained in depth in Garbage Collection on MSDN. The Garbage Collector tracks memory only in the Managed Heap.
No. AFAIK GC doesn't effect stack. It effects only HEAP memory. Stack frame will be created upon method calls and will be removed on method exit.
EDIT
This MSDN article explains how GC works in .NET framework.

Categories