{"id":13153,"date":"2010-08-13T07:00:00","date_gmt":"2010-08-13T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2010\/08\/13\/when-do-i-need-to-use-gc-keepalive\/"},"modified":"2010-08-13T07:00:00","modified_gmt":"2010-08-13T07:00:00","slug":"when-do-i-need-to-use-gc-keepalive","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20100813-00\/?p=13153","title":{"rendered":"When do I need to use GC.KeepAlive?"},"content":{"rendered":"<p>\nFinalization is the crazy wildcard in garbage collection.\nIt operates &#8220;behind the GC&#8221;,\nrunning after the GC has declared an object dead.\nThink about it: Finalizers run on objects that have no active references.\nHow can <code>this<\/code> be a reference to an object that has no references?\nThat&#8217;s just crazy-talk!\n<\/p>\n<p>\nFinalizers are a Ouija board,\npermitting dead objects to operate &#8220;from beyond the grave&#8221;\nand affect live objects.\nAs a result, when finalizers are involved, there is a lot of\ncreepy spooky juju going on,\nand you need to tread very carefully, or your soul will become\ncursed.\n<\/p>\n<p>\nLet&#8217;s step back and look at a different problem first.\nConsider this class which doesn&#8217;t do anything interesting\nbut works well enough for demonstration purposes:\n<\/p>\n<pre>\nclass Sample1 {\n private StreamReader sr;\n public Sample1(string file) : sr(new StreamReader(file)) { }\n public void Close() { sr.Close(); }\n public string NextLine() { return sr.ReadLine(); }\n}\n<\/pre>\n<p>\nWhat happens if one thread calls <code>Sample1.NextLine()<\/code>\nand another thread calls <code>Sample1.Close()<\/code>?\nIf the <code>NextLine()<\/code> call wins the race,\nthen you have a stream closed while it is in the middle of\nits <code>ReadLine<\/code> method.\nProbably not good.\nIf the <code>Close()<\/code> call wins the race,\nthen when the <code>NextLine()<\/code> call is made,\nyou end up reading from a closed stream.\nDefinitely not good.\nFinally, if the <code>NextLine()<\/code> call runs to\ncompletion before the <code>Close()<\/code>,\nthen the line is successfully read before the stream\nis closed.\n<\/p>\n<p>\nHaving this race condition is clearly an unwanted state of\naffairs since the result is unpredictable.\n<\/p>\n<p>\nNow let&#8217;s change the <code>Close()<\/code> method to a finalizer.\n<\/p>\n<pre>\nclass Sample2 {\n private StreamReader sr;\n public Sample2(string file) : sr(new StreamReader(file)) { }\n <font COLOR=\"blue\">~Sample2() { sr.Close(); }<\/font>\n public string NextLine() { return sr.ReadLine(); }\n}\n<\/pre>\n<p>\nRemember that we learned that an object becomes eligible for garbage collection\nwhen there are no active references to it,\nand that it can happen\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/08\/10\/10048149.aspx\">\neven while a method on the object is still active<\/a>.\nConsider this function:<\/p>\n<p><pre>\nstring FirstLine(string fileName) {\n Sample2 s = new Sample2(fileName);\n return s.NextLine();\n}\n<\/pre>\n<p>\nWe learned that the <code>Sample2<\/code> object becomes eligible\nfor collection during the execution of <code>NextLine()<\/code>.\nSuppose that the garbage collector runs and collects the object\nwhile <code>NextLine<\/code> is still running.\nThis could happen if <code>ReadLine<\/code> takes a long time,\nsay, because the hard drive needs to spin up or there is a network\nhiccup;\nor it could happen just because it&#8217;s not your lucky day\nand the garbage collector ran at just the wrong moment.\nSince this object has a finalizer, the finalizer runs\nbefore the memory is discarded, and the finalizer closes the\n<code>StreamReader<\/code>.\n<\/p>\n<p>\nBoom, we just hit the race condition we considered when\nwe looked at <code>Sample1<\/code>:\nThe stream was closed while it was being read from.\nThe garbage collector is a rogue thread that closes the stream\nat a bad time.\nThe problem occurs because the garbage collector doesn&#8217;t know\nthat the finalizer is going to <i>make changes to other objects<\/i>.\n<\/p>\n<p>\nClassically speaking,\nthere are three conditions which in combination lead to this problem:\n<\/p>\n<ol>\n<li>Containment: An entity&nbsp;<code>a<\/code>\n    retains a reference to another entity&nbsp;<code>b<\/code>.\n<\/li>\n<li>Incomplete encapsulation: The entity&nbsp;<code>b<\/code>\n    is visible to an entity outside <code>a<\/code>.\n<\/li>\n<li>Propagation of destructive effect:\n    Some operation performed on entity&nbsp;<code>a<\/code>\n    has an effect on entity&nbsp;<code>b<\/code> which alters\n    its proper usage (usually by rendering it useless).\n<\/li>\n<\/ol>\n<p>\nThe first condition (containment) is something you do without\na second&#8217;s thought.\nIf you look at any class, there&#8217;s a very high chance that it has,\namong its fields, a reference to another object.\n<\/p>\n<p>\nThe second condition (incomplete encapsulation)\nis also a common pattern.\nIn particular, if <code>b<\/code> is an object with methods,\nit will be visible to itself.\n<\/p>\n<p>\nThe third condition (propagation of destructive effect) is the tricky one.\nIf an operation on entity&nbsp;<code>a<\/code> has a damaging\neffect on entity&nbsp;<code>b<\/code>,\nthe code must be careful not to damage it while it&#8217;s still being\nused.\nThis is something you usually take care of explicitly,\nsince you&#8217;re the one who wrote the code that calls the destructive method.\n<\/p>\n<p>\nUnless the destructive method is a finalizer.\n<\/p>\n<p>\nIf the destructive method is a finalizer,\nthen\n<i>you do not have complete control over when it will run<\/i>.\nAnd it is one of the fundamental laws of the universe that events\nwill occur at the worst possible time.\n<\/p>\n<p>\nEnter <code>GC.KeepAlive()<\/code>.\nThe purpose of <code>GC.KeepAlive()<\/code> is to force the garbage\ncollector to treat the object as still live,\nthereby preventing it from being collected,\nand thereby preventing the finalizer from running prematurely.\n<\/p>\n<p>\n(Here&#8217;s the money sentence.)\nYou need to use <code>GC.KeepAlive<\/code> when the finalizer\nfor an object has a destructive effect on a contained object.\n<\/p>\n<p>\nThe problem is that it&#8217;s not always clear which objects have\nfinalizers which have destructive effect on a contained object.\nThere are some cases where you can suspect this is happening\ndue to the nature of the object itself.\nFor example, if the object manages something external to the CLR,\nthen its finalizer will probably destroy the external object.\nBut there can be other cases where the need for <code>GC.KeepAlive<\/code>\nis not obvious.\n<\/p>\n<p>\nA much cleaner solution than using <code>GC.KeepAlive<\/code>\nis to use the <code>IDisposable<\/code> interface,\nformalized by the <code>using<\/code> keyword.\nEverybody knows that the <code>using<\/code> keyword ensures that the\nobject being used is disposed at the end of the block.\nBut it&#8217;s also the case (and it is this behavior that is important today)\nthat the <code>using<\/code> keyword also <i>keeps the object alive\nuntil the end of the block<\/i>.\n(Why?\nBecause the object needs to be alive so that we can call <code>Dispose<\/code>\non it!)\n<\/p>\n<p>\nThis is one of the reasons I don&#8217;t like finalizers.\nSince they operate underneath the GC,\nthey undermine many principles of garbage collected systems.\n(See also\n<a HREF=\"http:\/\/blogs.msdn.com\/clyon\/archive\/2006\/04\/25\/583698.aspx\">\n<i>resurrection<\/i><\/a>.)\nAs we saw earlier,\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/08\/09\/10047586.aspx\">\na correctly-written program cannot rely on side effects of a finalizer<\/a>,\nso in theory all finalizers could be nop&#8217;d out\nwithout affecting correctness.\n<\/p>\n<p>\nThe garbage collector purist in me also doesn&#8217;t like finalizers\nbecause they prevent the running time of a garbage collector to be\nproportional to the amount of <i>live<\/i> data,\nlike say in a classic two-space collector.\n(There is also a small constant associated with the amount of <i>dead<\/i>\ndata, which means that the overall complexity is proportional to the\namount of <i>total data<\/i>.)\n<\/p>\n<p>\nIf I ruled the world, I would decree that the only thing you can do in\na finalizer is perform some tests to ensure that all the associated\nexternal resources have already been explicitly released, and if not, raise\na fatal exception:\n<code>System.Exception.Resource&shy;Leak<\/code>.\n<\/p>\n<p>\n<b>Bonus reading<\/b>\n<\/p>\n<ul>\n<li>\n    <a HREF=\"http:\/\/blogs.msdn.com\/kimhamil\/archive\/2008\/03\/15\/the-often-non-difference-between-close-and-dispose.aspx\">\n    The often non-difference between Close and Dispose<\/a>.\n<\/li>\n<li>\n    <a HREF=\"http:\/\/blogs.msdn.com\/visualstudio\/archive\/2010\/03\/01\/marshal-releasecomobject-considered-dangerous.aspx\">\n    Marshal.ReleaseComObject considered dangerous<\/a>.\n<\/li>\n<\/ul><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Finalization is the crazy wildcard in garbage collection. It operates &#8220;behind the GC&#8221;, running after the GC has declared an object dead. Think about it: Finalizers run on objects that have no active references. How can this be a reference to an object that has no references? That&#8217;s just crazy-talk! Finalizers are a Ouija board, [&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":[25],"class_list":["post-13153","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Finalization is the crazy wildcard in garbage collection. It operates &#8220;behind the GC&#8221;, running after the GC has declared an object dead. Think about it: Finalizers run on objects that have no active references. How can this be a reference to an object that has no references? That&#8217;s just crazy-talk! Finalizers are a Ouija board, [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/13153","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=13153"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/13153\/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=13153"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=13153"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=13153"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}