{"id":13173,"date":"2010-08-11T07:00:00","date_gmt":"2010-08-11T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2010\/08\/11\/how-do-i-get-the-reference-count-of-a-clr-object\/"},"modified":"2010-08-11T07:00:00","modified_gmt":"2010-08-11T07:00:00","slug":"how-do-i-get-the-reference-count-of-a-clr-object","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20100811-00\/?p=13173","title":{"rendered":"How do I get the reference count of a CLR object?"},"content":{"rendered":"<p>\nA customer asked the rather enigmatic question (with no context):\n<\/p>\n<blockquote CLASS=\"q\">\n<p>\nIs there a way to get the reference count of an object in .Net?\n<\/p>\n<p>\nThanks,<br \/>\nBob Smith<br \/>\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2010\/01\/27\/9953807.aspx\">Senior Developer<\/a><br \/>\nContoso\n<\/p>\n<\/blockquote>\n<p>\nThe CLR does not maintain reference counts, so there is no reference\ncount to &#8220;get&#8221;.\nThe garbage collector only cares about whether an object\nhas zero references\nor at least one reference.\nIt doesn&#8217;t care if there is one, two, twelve, or five hundred&mdash;from\nthe point of view of the garbage collector, one is as good as\nfive hundred.\n<\/p>\n<p>\nThe customer replied,\n<\/p>\n<blockquote CLASS=\"q\">\n<p>\nI am aware of that, yet the mechanism is somehow implemented by the GC&#8230;\n<\/p>\n<p>\nWhat I want to know is whether at a certain point\nthere is more then one variable pointing to the same object.\n<\/p>\n<\/blockquote>\n<p>\nAs already noted, the GC does not implement the &#8220;count the number\nof references to this object&#8221; algorithm.\nIt only implements the &#8220;Is it definitely safe to reclaim the memory\nfor his object?&#8221; algorithm.\nA null garbage collector always answers &#8220;No.&#8221;\nA tracing collector looks for references, but it only cares\n<i>whether<\/i> it found one, not how many it found.\n<\/p>\n<p>\nThe discussion of &#8220;variables pointing to the same objects&#8221; is\nsomewhat confused, because you can have references to an object\nfrom things other than variables.\nParameters to a method contain references,\nthe implicit <code>this<\/code> is also a reference,\nand partially-evaluated expressions also contain references.\n(During execution of the line <code>string s = o.ToString();<\/code>,\nat the point immediately after <code>o.ToString()<\/code> returns\nand before the result is assigned to <code>s<\/code>,\nthe string has an active reference but it isn&#8217;t stored in any\nvariable.)\nAnd as we saw earlier,\n<a>\nmerely storing a reference in a variable doesn&#8217;t prevent the\nobject from being collected<\/a>.\n<\/p>\n<p>\nIt&#8217;s clear that this person\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2006\/03\/23\/558887.aspx\">\nsolved half of his problem, and just needs help with the other half,\nthe half that doesn&#8217;t make any sense<\/a>.\n(I like how he immediately weakened his request from\n&#8220;I want the exact reference count&#8221;\nto &#8220;I want to know if it is greater than one.&#8221;\nBecause as we all know, the best way to solve a problem is to\nreduce it to an even harder problem.)\n<\/p>\n<p>\nAnother person used some psychic powers to figure out what the real\nproblem is:\n<\/p>\n<blockquote CLASS=\"m\"><p>\nIf I am reading properly into what you mean,\nyou may want to check out the <code>Weak&shy;Reference<\/code> class.\nThis lets you determine whether an object has been collected.\nNote that you don&#8217;t get access to a reference count; it&#8217;s a\nzero\/nonzero thing.\nIf the <code>Weak&shy;Reference<\/code> is empty, it means the object has\nbeen collected.\nYou don&#8217;t get a chance to act upon it\n(as you would if you were the last one holding a reference to it).\n<\/p><\/blockquote>\n<p>\nThe customer explained that he tried\n<code>Weak&shy;Reference<\/code>, but it didn&#8217;t work.\n(By withholding this information, the customer made the mistake of\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/04\/22\/10000406.aspx\">\nnot saying what he already tried and why it didn&#8217;t work<\/a>.)\n<\/p>\n<blockquote CLASS=\"q\">\n<p>\nWell this is exactly the problem:\nI instantiate an object and then create a\n<code>Weak&shy;Reference<\/code> to it (global variable).\n<\/p>\n<p>\nThen at some point the object is released\n(set to null, disposed, erased from the face of the earth, you name it)\nyet if I check the <code>Is&shy;Alive<\/code> property it still returns true.\n<\/p>\n<p>\nOnly if I explicitly call to <code>GC.Collect(0)<\/code>\nor greater before the check it is disposed.\n<\/p>\n<\/blockquote>\n<p>\nThe customer still hasn&#8217;t let go of the concept of reference\ncounting, since he says that the object is &#8220;released&#8221;.\nIn a garbage-collected system, object are not released;\nrather, you simply stop referencing them.\nAnd disposing of an object still maintains a reference;\ndisposing just invokes the <code>IDisposable.Dispose<\/code> method.\n<\/p>\n<pre>\nFileStream fs = new FileStream(fileName);\nusing (fs) {\n ...\n}\n<\/pre>\n<p>\nAt the end of this code fragment, the <code>File&shy;Stream<\/code> has\nbeen disposed, but there is still a reference to it in the <code>fs<\/code>\nvariable.\nMind you, that reference isn&#8217;t very useful, since there isn&#8217;t much\nyou can do with a disposed object,\nEven if you rewrite the fragment as\n<\/p>\n<pre>\nusing (FileStream fs = new FileStream(fileName)) {\n ...\n}\n<\/pre>\n<p>\nthe variable <code>fs<\/code> still exists after the close-brace;\nit simply has gone out of scope (i.e., you can&#8217;t access it any more).\n<a HREF=\"http:\/\/blogs.msdn.com\/ericlippert\/archive\/2009\/08\/03\/what-s-the-difference-part-two-scope-vs-declaration-space-vs-lifetime.aspx\">\nScope is not the same as lifetime<\/a>.\nOf course, the optimizer can step in and make the object\neligible for collection\nonce the value becomes inaccessible, but there is no requirement that\nthis optimization be done.\n<\/p>\n<p>\nThe fact that the <code>Is&shy;Alive<\/code> property says <code>true<\/code>\neven after all known references have been destroyed is also no surprise.\nThe environment does not check whether an object&#8217;s last reference\nhas been made inaccessible every time a reference changes.\nOne of the major performance benefits of garbage collected systems\ncomes from the de-amortization of object lifetime determination.\nInstead of maintaining lifetime information about an object continuously\n(spending a penny each time a reference is created or destroyed),\nit saves up those pennies and splurges on a few dollars every so often.\nThe calculated risk (which usually pays off)\nis that the rate of penny-saving makes up for the occasional splurges.\n<\/p>\n<p>\nIt does mean that between the splurges, the garbage collector does not\nknow whether an object has outstanding references or not.\nIt doesn&#8217;t find out until it does a collection.\n<\/p>\n<p>\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/08\/09\/10047586.aspx\">\nThe null garbage collector<\/a>\ntakes this approach to an extreme by simply hoarding pennies and\nnever spending them. It saves a lot of money but consumes a lot of memory.\nThe other extreme (common in unmanaged environments) is to spend\nthe pennies as soon as possible.\nIt spends a lot of money but reduces memory usage to the absolute minimum.\nThe designers of a garbage collector work to find the right balance\nbetween these two extremes,\nsaving money overall while still keeping memory usage at a reasonable level.\n<\/p>\n<p>\nThe customer appears to have misinterpreted what the <code>Is&shy;Alive<\/code>\nproperty means.\nThe property doesn&#8217;t say whether there are any references to the object.\nIt says\n<a HREF=\"http:\/\/msdn.microsoft.com\/system.weakreference.isalive.aspx\">\nwhether the object has been garbage collected<\/a>.\nSince the garbage collector can run at any time,\n<a HREF=\"http:\/\/blogs.msdn.com\/clyon\/archive\/2006\/04\/20\/580255.aspx\">\nthere is nothing meaningful you can conclude if\n<code>Is&shy;Alive<\/code> returns <code>true<\/code><\/a>,\nsince it can transition from alive to dead while you&#8217;re talking about it.\nOn the other hand, once it&#8217;s dead, it stays dead;\nit is valid to take action when <code>Is&shy;Alive<\/code> is <code>false<\/code>.\n(Note that there are two types of <code>Weak&shy;Reference<\/code>;\nthe difference is\n<a HREF=\"http:\/\/blogs.msdn.com\/clyon\/archive\/2006\/05\/01\/588001.aspx\">\nwhen they issue the death certificate<\/a>.)\n<\/p>\n<p>\nThe name <code>Is&shy;Alive<\/code> for the property could be viewed\nas misleading if you just look at the property name without reading the\naccompanying documentation.\nPerhaps a more accurate (but much clumsier) name would have been\n<code>Has&shy;Not&shy;Been&shy;Collected<\/code>.\nThe theory is, presumably, that\nif you&#8217;re using an advanced\nclass like <code>Weak&shy;Reference<\/code>, which works &#8220;at the GC level&#8221;,\nyou need to understand the GC.\n<\/p>\n<p>\nThe behavior the customer is seeing is correct.\nThe odds that the garbage collector has run between annihilating\nthe last live reference and checking the <code>Is&shy;Alive<\/code> property\nis pretty low,\nso when you ask whether the object has been collected,\nthe answer will be No.\nOf course, forcing a collection will cause the garbage collector to run,\nand that&#8217;s what does the collection and sets <code>Is&shy;Alive<\/code> to\n<code>false<\/code>.\nMind you, forcing the collection to take place\nmesses up the careful penny-pinching\nthe garbage collector has been performing.\nYou forced it to pay for a collection before it had finished saving\nup for it, putting the garbage collector in debt.\n(Is there a garbage collector debt collector?)\nAnd the effect of a garbage collector going into debt is that your program\nruns slower than it would have if you had let the collector spend\nits money on its own terms.\n<\/p>\n<p>\nNote also that forcing a generation-zero collection does not\nguarantee that the object in question will be collected:\nIt may have been promoted into a higher generation.\n(Generational garbage collection takes advantage of typical real-world\nobject lifetime profiles\nby spending only\nfifty cents on a partial collection rather than a whole dollar\non a full collection.\nAs a rough guide, the cost of a collection is proportional to the number\nof live object scanned,\nso the most efficient collections are those which find mostly dead objects.)\nForcing an early generation-zero collection messes up the careful\nbalance between cheap-but-partial collections and\nexpensive-and-thorough collections,\ncausing objects to get promoted into higher generations before\nthey really deserve it.\n<\/p>\n<p>\nOkay, that was a long discussion of a short email thread.\nMaybe tomorrow I&#8217;ll do a better job of keeping things short.\n<\/p>\n<p>\n<b>Bonus chatter<\/b>:\nIn addition to the <code>Weak&shy;Reference<\/code> class,\nthere is also the <code>GC&shy;Handle<\/code> structure.\n<\/p>\n<p>\n<b>Bonus reading<\/b>:\n<a HREf=\"http:\/\/blogs.msdn.com\/maoni\/\">\nMaoni&#8217;s WebLog<\/a>\ngoes into lots of detail on the internals of the CLR garbage\ncollector.\n<a HREF=\"http:\/\/blogs.msdn.com\/dougste\/\">\nDoug Stewart<\/a>\ncreated this\n<a HREF=\"http:\/\/blogs.msdn.com\/dougste\/archive\/2010\/02\/18\/an-index-to-maoni-s-blog-posts-about-the-gc.aspx\">\nhandy index<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A customer asked the rather enigmatic question (with no context): Is there a way to get the reference count of an object in .Net? Thanks, Bob Smith Senior Developer Contoso The CLR does not maintain reference counts, so there is no reference count to &#8220;get&#8221;. The garbage collector only cares about whether an object has [&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-13173","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>A customer asked the rather enigmatic question (with no context): Is there a way to get the reference count of an object in .Net? Thanks, Bob Smith Senior Developer Contoso The CLR does not maintain reference counts, so there is no reference count to &#8220;get&#8221;. The garbage collector only cares about whether an object has [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/13173","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=13173"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/13173\/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=13173"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=13173"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=13173"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}