{"id":13193,"date":"2010-08-10T07:00:00","date_gmt":"2010-08-10T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2010\/08\/10\/when-does-an-object-become-available-for-garbage-collection\/"},"modified":"2010-08-10T07:00:00","modified_gmt":"2010-08-10T07:00:00","slug":"when-does-an-object-become-available-for-garbage-collection","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20100810-00\/?p=13193","title":{"rendered":"When does an object become available for garbage collection?"},"content":{"rendered":"<p>\nAs we saw last time,\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/08\/09\/10047586.aspx\">\ngarbage collection is a method for\nsimulating an infinite amount of memory\nin a finite amount of memory<\/a>.\nThis simulation is performed by reclaiming memory once the environment\ncan determine that the program wouldn&#8217;t notice that the memory was\nreclaimed.\nThere are a variety of mechanism for determining this.\nIn a basic tracing collector,\nthis determination is made by taking the objects which the\nprogram has definite references to, then tracing references from those\nobjects, contining transitively until all accessible objects are found.\nBut what looks like a definite reference in your code may not actually\nbe a definite reference in the virtual machine:\nJust because a variable is in scope doesn&#8217;t mean that it is live.\n<\/p>\n<pre>\nclass SomeClass {\n ...\n string SomeMethod(string s, bool reformulate)\n {\n  OtherClass o = new OtherClass(s);\n  string result = Frob(o);\n  if (reformulate) Reformulate();\n  return result;\n }\n}\n<\/pre>\n<p>\nFor the purpose of this discussion,\nassume that the <code>Frob<\/code> method does not retain a reference\nto the object&nbsp;<code>o<\/code> passed as a parameter.\nWhen does the <code>OtherClass<\/code> object&nbsp;<code>o<\/code>\nbecome eligible for collection?\nA na&iuml;ve answer would be that it becomes eligible for collection\nat the closing-brace of the <code>SomeMethod<\/code> method,\nsince that&#8217;s when the last reference (in the variable <code>o<\/code>)\ngoes out of scope.\n<\/p>\n<p>\nA less na&iuml;ve answer would be that it become eligible for collection\nafter the return value from <code>Frob<\/code> is stored to the local\nvariable <code>result<\/code>, because that&#8217;s the last line of code which\nuses the variable&nbsp;<code>o<\/code>.\n<\/p>\n<p>\nA closer study would show that it becomes eligible for collection\neven sooner:\nOnce the call to <code>Frob<\/code> returns,\nthe variable&nbsp;<code>o<\/code> is no longer accessed,\nso the object could be collected even before the result of the call\nto <code>Frob<\/code> is stored into the local variable <code>result<\/code>.\nOptimizing compilers have known this for quite some time,\nand there is a strong likelihood that the variables\n<code>o<\/code>&nbsp;and&nbsp;<code>result<\/code>\nwill occupy the same memory since their lifetimes do not overlap.\nUnder such conditions,\nthe code generation for the statement could very well be something\nlike this:\n<\/p>\n<pre>\n  mov ecx, esi        ; load \"this\" pointer into ecx register\n  mov edx, [ebp-8]    ; load parameter (\"o\") into edx register\n  call SomeClass.Frob ; call method\n  mov [ebp-8], eax    ; re-use memory for \"o\" as \"result\"\n<\/pre>\n<p>\nBut this closer study wasn&#8217;t close enough.\nThe <code>OtherClass<\/code> object&nbsp;<code>o<\/code>\nbecomes eligible for collection even before the call to <code>Frob<\/code>\nreturns!\nIt is certainly eligible for collection at the point of the <code>ret<\/code>\ninstruction which ends the <code>Frob<\/code> function:\nAt that point,\nthe <code>Frob<\/code> has finished using the object and won&#8217;t access\nit again.\nAlthough somewhat of a technicality, it does illustrate that\n<\/p>\n<blockquote CLASS=\"m\"><p>\nAn object in a block of code\ncan become eligible for collection <i>during execution of a function\nit called<\/i>.\n<\/p><\/blockquote>\n<p>\nBut let&#8217;s dig deeper.\nSuppose that <code>Frob<\/code> looked like this:\n<\/p>\n<pre>\nstring Frob(OtherClass o)\n{\n string result = FrobColor(o.GetEffectiveColor());\n}\n<\/pre>\n<p>\nWhen does the <code>OtherClass<\/code> object become eligible for\ncollection?\nWe saw above that it is certainly eligible for collection as soon as\n<code>FrobColor<\/code> returns, because the <code>Frob<\/code>\nmethod doesn&#8217;t use <code>o<\/code> any more after that point.\nBut in fact it is eligible for collection when the call\nto <code>GetEffectiveColor<\/code> returns&mdash;even before the\n<code>FrobColor<\/code> method is called&mdash;because the <code>Frob<\/code>\nmethod doesn&#8217;t use it once it gets the effective color.\nThis illustrates that\n<\/p>\n<blockquote CLASS=\"m\"><p>\nA parameter to a method can become eligible for collection\n<i>while the method is still executing<\/i>.\n<\/p><\/blockquote>\n<p>\nBut wait, is that the earliest the <code>OtherClass<\/code> object\nbecomes eligible for collection?\nSuppose that the <code>OtherClass.GetEffectiveColor<\/code> method\nwent like this:\n<\/p>\n<pre>\nColor GetEffectiveColor()\n{\n Color color = this.Color;\n for (OtherClass o = this.Parent; o != null; o = o.Parent) {\n  color = BlendColors(color, o.Color);\n }\n return color;\n}\n<\/pre>\n<p>\nNotice that the method doesn&#8217;t access any members from its <code>this<\/code>\npointer after the assignment <code>o = this.Parent<\/code>.\nAs soon as the method retrieves the object&#8217;s parent,\nthe object isn&#8217;t used any more.\n<\/p>\n<pre>\n  push ebp                    ; establish stack frame\n  mov ebp, esp\n  push esi\n  push edi\n  mov esi, ecx                ; enregister \"this\"\n  mov edi, [ecx].color        ; color = this.Color \/\/ inlined\n  jmp looptest\nloop:\n  mov ecx, edi                ; load first parameter (\"color\")\n  mov edx, [esi].color        ; load second parameter (\"o.Color\")\n  call OtherClass.BlendColors ; BlendColors(color, o.Color)\n  mov edi, eax\nlooptest:\n  mov esi, [esi].parent       ; o = this.Parent (or o.Parent) \/\/ inlined\n  \/\/ \"this\" is now eligible for collection\n  test esi, esi               ; if o == null\n  jnz loop                    ; then rsetart loop\n  mov eax, edi                ; return value\n  pop edi\n  pop esi\n  pop ebp\n  ret\n<\/pre>\n<p>\nThe last thing we ever do with the <code>Other&shy;Class<\/code>\nobject (presented in the <code>Get&shy;Effective&shy;Color<\/code>\nfunction by the keyword <code>this<\/code>)\nis fetch its parent.\nAs soon that&#8217;s done\n(indicated at the point of the comment, when the line is reached\nfor the first time),\nthe object becomes eligible for collection.\nThis illustrates the perhaps-surprising result that\n<\/p>\n<blockquote CLASS=\"m\"><p>\nAn object can become eligible for collection\n<i>during execution of a method on that very object<\/i>.\n<\/p><\/blockquote>\n<p>\nIn other words, it is possible for a method to have its\n<code>this<\/code> object collected out from under it!\n<\/p>\n<p>\nA crazy way of thinking of when an object becomes eligible for\ncollection is that it happens once\nmemory corruption in the object\nwould have no effect on the program.\n(Or, if the object has a finalizer, that memory corruption would\naffect only the finalizer.)\nBecause if memory corruption would have no effect,\nthen that means you never use the values any more,\nwhich means that the memory may as well have been\nreclaimed out from under you for all you know.\n<\/p>\n<p>\nA weird real-world analogy:\nThe garbage collector can collect your diving board as soon as the\ndiver touches it for the last time&mdash;even if the diver is still\nin the air!\n<\/p>\n<p>\nA customer encountered the\n<code>Call&shy;GC&shy;Keep&shy;Alive&shy;When&shy;Using&shy;Native&shy;Resources<\/code>\nFxCop rule\nand didn&#8217;t understand how it was possible for the GC to\ncollect an object while one of its methods was still running.\n&#8220;Isn&#8217;t <code>this<\/code> part of the root set?&#8221;\n<\/p>\n<p>\nAsking whether any particular value is or is not part of the root\nset is confusing the definition of garbage collection with its\nimplementation.\n&#8220;Don&#8217;t think of GC as tracing roots.\nThink of GC as removing things you aren&#8217;t using any more.&#8221;\n<\/p>\n<p>\nThe customer responded,\n&#8220;Yes, I understand conceptually that it becomes eligible for\ncollection, but how does the garbage collector know that?\nHow does it know that the <code>this<\/code> object is not used\nany more?\nIsn&#8217;t that determined by tracing from the root set?&#8221;\n<\/p>\n<p>\nRemember, the GC is in cahoots with the JIT.\nThe JIT might decide to &#8220;help out&#8221; the GC by\nreusing the stack slot which previously held an object\nreference,\nleaving no reference on the stack and therefore no reference\nin the root set.\nEven if the reference is left on the stack, the JIT can leave\nsome metadata behind that tells the GC, &#8220;If you see the instruction\npointer in this range, then ignore the reference in this slot\nsince it&#8217;s a dead variable,&#8221;\nsimilar to how in unmanaged code on non-x86 platforms, metadata\nis used to guide structured exception handling.\n(And besides, the <code>this<\/code> parameter isn&#8217;t even passed\non the stack in the first place.)\n<\/p>\n<p>\nThe customer replied, &#8220;Gotcha. Very cool.&#8221;\n<\/p>\n<p>\nAnother customer asked,\n&#8220;Is there a way to get a reference to the instance being called\nfor each frame in the stack? (Static methods excepted, of course.)&#8221;\nA different customer asked roughly the same question, but in\na different context:\n&#8220;I want my method to walk up the stack, and if its caller is\n<code>OtherClass.Foo<\/code>, I want to get the <code>this<\/code>\nobject for <code>OtherClass.Foo<\/code> so I can query additional\nproperties from it.&#8221;\nYou now know enough to answer these questions yourself.\n<\/p>\n<p>\nBonus:\nA different customer asked,\n&#8220;The <code>Stack&shy;Frame<\/code> object lets me get the method that\nis executing in the stack frame,\nbut how do I get the parameters passed to that method?&#8221;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As we saw last time, garbage collection is a method for simulating an infinite amount of memory in a finite amount of memory. This simulation is performed by reclaiming memory once the environment can determine that the program wouldn&#8217;t notice that the memory was reclaimed. There are a variety of mechanism for determining this. In [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[26],"class_list":["post-13193","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>As we saw last time, garbage collection is a method for simulating an infinite amount of memory in a finite amount of memory. This simulation is performed by reclaiming memory once the environment can determine that the program wouldn&#8217;t notice that the memory was reclaimed. There are a variety of mechanism for determining this. In [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/13193","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=13193"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/13193\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=13193"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=13193"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=13193"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}