{"id":4721,"date":"2015-09-16T13:00:11","date_gmt":"2015-09-16T13:00:11","guid":{"rendered":"http:\/\/writeasync.net\/?p=4721"},"modified":"2015-09-16T04:24:52","modified_gmt":"2015-09-16T04:24:52","slug":"dictionary-and-memory-usage","status":"publish","type":"post","link":"https:\/\/writeasync.net\/?p=4721","title":{"rendered":"Dictionary and memory usage"},"content":{"rendered":"<p>Consider this code using <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/xfhwa508(v=vs.110).aspx\"><code>Dictionary&lt;TKey, TValue&gt;<\/code><\/a>:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate static void DictionaryTest()\r\n{\r\n    var c = new Dictionary&lt;int, int&gt;();\r\n    Stopwatch stopwatch = Stopwatch.StartNew();\r\n    for (int b = 1; b &lt; 100000000; b &lt;&lt;= 1)\r\n    {\r\n        for (int i = 0; i &lt; b; ++i)\r\n        {\r\n            c.Add(i, i);\r\n        }\r\n\r\n        \/\/ Get memory usage when full\r\n        long mem1 = GC.GetTotalMemory(false);\r\n\r\n        c.Clear();\r\n\r\n        \/\/ Get memory usage after GC when empty\r\n        int cap = GetCapacity(c);\r\n        long mem2 = GC.GetTotalMemory(true);\r\n\r\n        Console.WriteLine(&quot;&#x5B;{0:0.000000}] {1:0000000000} -&gt; {2:0000000000} (cap={3:00000000})&quot;, stopwatch.Elapsed.TotalSeconds, mem1, mem2, cap);\r\n    }\r\n}\r\n\r\nprivate static int GetCapacity(Dictionary&lt;int, int&gt; c)\r\n{\r\n    var field = c.GetType().GetField(&quot;buckets&quot;, BindingFlags.NonPublic | BindingFlags.Instance);\r\n    return ((int&#x5B;])field.GetValue(c)).Length;\r\n}\r\n<\/pre>\n<p>One might assume that the capacity (actually <a href=\"http:\/\/research.cs.vt.edu\/AVresearch\/hashing\/buckethash.php\">bucket<\/a> count in this case) and memory usage will stabilize after repeatedly filling then clearing the collection. Unfortunately, this is not the case. Here is the output on my system (compiling in Release mode as a 64-bit EXE):<\/p>\n<pre>[0.000401] 0000055600 -> 0000046240 (cap=00000003)\r\n[0.001003] 0000062624 -> 0000057784 (cap=00000003)\r\n[0.001152] 0000065976 -> 0000057864 (cap=00000007)\r\n[0.001283] 0000066056 -> 0000058064 (cap=00000017)\r\n[0.001410] 0000066256 -> 0000058064 (cap=00000017)\r\n[0.001546] 0000066256 -> 0000058464 (cap=00000037)\r\n[0.001674] 0000066656 -> 0000059504 (cap=00000089)\r\n[0.001801] 0000067696 -> 0000061664 (cap=00000197)\r\n[0.001934] 0000078048 -> 0000066344 (cap=00000431)\r\n[0.002072] 0000089288 -> 0000076104 (cap=00000919)\r\n[0.002228] 0000123432 -> 0000096344 (cap=00001931)\r\n[0.002421] 0000185616 -> 0000138704 (cap=00004049)\r\n[0.002684] 0000315384 -> 0000226104 (cap=00008419)\r\n[0.002906] 0000234296 -> 0000226104 (cap=00008419)\r\n[0.003461] 0000584784 -> 0000408128 (cap=00017519)\r\n[0.004278] 0001143496 -> 0000784808 (cap=00036353)\r\n[0.005701] 0002301704 -> 0001566368 (cap=00075431)\r\n[0.008462] 0004703384 -> 0003186488 (cap=00156437)\r\n[0.013970] 0009683744 -> 0006546728 (cap=00324449)\r\n[0.025663] 0020011576 -> 0013514288 (cap=00672827)\r\n[0.049834] 0041427824 -> 0027963008 (cap=01395263)\r\n[0.099440] 0085836264 -> 0057922728 (cap=02893249)\r\n[0.205534] 0177920424 -> 0120047168 (cap=05999471)\r\n[0.412975] 0360034456 -> 0240036728 (cap=11998949)\r\n[0.831726] 0720003176 -> 0480015888 (cap=23997907)\r\n[1.650525] 1439941256 -> 0959974808 (cap=47995853)\r\n[3.272893] 2879817856 -> 1919892488 (cap=95991737)<\/pre>\n<p>As it turns out, memory just keeps growing and growing with the dictionary capacity never getting any smaller. (Side note, <a href=\"http:\/\/blogs.msdn.com\/b\/dcook\/\">Doug Cook<\/a> would probably roll his eyes at <a href=\"http:\/\/blogs.msdn.com\/b\/dcook\/archive\/2007\/09\/09\/hashes-and-tables-and-primes-oh-my.aspx\">all those prime number bucket sizes<\/a>.)<\/p>\n<p>Unfortunately, <code>Dictionary<\/code> does not provide access to its <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/y52x03h2(v=vs.110).aspx\"><code>Capacity<\/code><\/a> or a <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/ms132207(v=vs.110).aspx\"><code>TrimExcess()<\/code><\/a> method <a href=\"http:\/\/stackoverflow.com\/questions\/1625122\/why-is-there-no-dictionary-trimexcess\">like <code>List<\/code> does<\/a>.<\/p>\n<p>For this reason, if you need a dictionary which widely varies in size over its lifetime, you may want to consider replacing the old, worn out one occasionally with a fresh new one:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ Either replace the reference rather than clearing...\r\nexisting = new Dictionary&lt;int, int&gt;();\r\n\r\n\/\/ ...or copy the contents to a new one\r\nvar newOne = new Dictionary&lt;int, int&gt;(existing);\r\nexisting = newOne;\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Consider this code using Dictionary&lt;TKey, TValue&gt;: private static void DictionaryTest() { var c = new Dictionary&lt;int, int&gt;(); Stopwatch stopwatch = Stopwatch.StartNew(); for (int b = 1; b &lt; 100000000; b &lt;&lt;= 1) { for (int i = 0; i &lt;&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[91,71],"tags":[],"class_list":["post-4721","post","type-post","status-publish","format-standard","hentry","category-design","category-diagnostics"],"_links":{"self":[{"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/4721","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4721"}],"version-history":[{"count":0,"href":"https:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/4721\/revisions"}],"wp:attachment":[{"href":"https:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4721"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4721"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4721"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}