<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>mikeash.com pyblog/autorelease-is-fast.html comments</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>mikeash.com Recent Comments</description><lastBuildDate>Mon, 17 Aug 2026 11:31:56 GMT</lastBuildDate><generator>PyRSS2Gen-1.0.0</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>arri - 2011-07-02 09:07:08</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>good to finally 'know' - i was suspecting something like this and acting accordingly. thanks for setting it straight.
&lt;br /&gt;
&lt;br /&gt;perhaps interesting to note that the line seems to have become flatter with more recent iterations of the OS (Objc2) and hardware.
&lt;br /&gt;but the trend didn't change.
&lt;br /&gt;
&lt;br /&gt;this is on a mid-2009 13" MBP (5,5) 2.26 Ghz/4Gb running 10.6.8
&lt;br /&gt;(64bit)
&lt;br /&gt;
&lt;br /&gt;1 - 1000000  - 0.352932
&lt;br /&gt;10 - 100000  - 0.335275
&lt;br /&gt;100 - 10000  - 0.328813
&lt;br /&gt;1000 - 1000  - 0.328538
&lt;br /&gt;10000 - 100  - 0.333225
&lt;br /&gt;100000 - 10  - 0.343582
&lt;br /&gt;1000000 - 1  - 0.395972
&lt;br /&gt;</description><guid isPermaLink="true">b8c338659623a22584ef236e5e16e68a</guid><pubDate>Sat, 02 Jul 2011 09:07:08 GMT</pubDate></item><item><title>mikeash - 2010-09-28 02:49:09</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>Two reasons:
&lt;br /&gt;
&lt;br /&gt;1) It's not always possible to avoid autoreleasing objects. Sometimes you have to return non-retained objects to the caller, and the frameworks will autorelease objects in many methods without your control or consent.
&lt;br /&gt;
&lt;br /&gt;2) It's a lot more convenient to use factory methods instead of alloc/init/release. The only reason not to is to keep your memory high-water-mark reasonably low, and the whole point of this performance measurement is that you can achieve that with a liberal sprinkling of autorelease pools instead. (And achieve it &lt;i&gt;better&lt;/i&gt;, since the framework may autorelease objects beyond your control.)</description><guid isPermaLink="true">1326d75c6014e72e092ffe4edfa6e599</guid><pubDate>Tue, 28 Sep 2010 02:49:09 GMT</pubDate></item><item><title>Mason - 2010-09-28 02:18:20</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>I don't see why any of this is necessary if, as good boys, we all just stick clear of factory-methods, and [obj release] our temp objects each iteration. Done, done and done a lot quicker than any autoreleasepool method.</description><guid isPermaLink="true">9274be47b8e835034a8b31c16036701c</guid><pubDate>Tue, 28 Sep 2010 02:18:20 GMT</pubDate></item><item><title>mikeash - 2010-06-30 04:55:25</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>Very cool, I'm impressed at how closely it follows the original curve even on completely different hardware.</description><guid isPermaLink="true">8af029a14a8bc2c11eb001a9040b822b</guid><pubDate>Wed, 30 Jun 2010 04:55:25 GMT</pubDate></item><item><title>Xing Pengfei - 2010-06-30 04:24:23</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>Great post, just tried on iPhone 3GS, and get the following data which matches the one mentioned in your article. Thanks!
&lt;br /&gt;
&lt;br /&gt;===== warming up whatever caches may exist, ignore this
&lt;br /&gt;Testing 1000 iterations, allocating 1 objects per iteration...done
&lt;br /&gt;total time: 0.010807 seconds
&lt;br /&gt;
&lt;br /&gt;===== done, results follow
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;Testing 1 iterations, allocating 1000000 objects per iteration...done
&lt;br /&gt;total time: 9.243073 seconds
&lt;br /&gt;
&lt;br /&gt;Testing 10 iterations, allocating 100000 objects per iteration...done
&lt;br /&gt;total time: 9.074250 seconds
&lt;br /&gt;
&lt;br /&gt;Testing 100 iterations, allocating 10000 objects per iteration...done
&lt;br /&gt;total time: 9.706995 seconds
&lt;br /&gt;
&lt;br /&gt;Testing 1000 iterations, allocating 1000 objects per iteration...done
&lt;br /&gt;total time: 8.522664 seconds
&lt;br /&gt;
&lt;br /&gt;Testing 10000 iterations, allocating 100 objects per iteration...done
&lt;br /&gt;total time: 5.443504 seconds
&lt;br /&gt;
&lt;br /&gt;Testing 100000 iterations, allocating 10 objects per iteration...done
&lt;br /&gt;total time: 6.312481 seconds
&lt;br /&gt;
&lt;br /&gt;Testing 1000000 iterations, allocating 1 objects per iteration...done
&lt;br /&gt;total time: 11.958108 seconds</description><guid isPermaLink="true">e7696857d40967661fe26b98eda3f0e9</guid><pubDate>Wed, 30 Jun 2010 04:24:23 GMT</pubDate></item><item><title>leeg - 2006-12-14 15:47:00</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>I&amp;amp;#8217;d had similar thoughts about ARPs and had decided to test that on the GNU runtime.  For fair comparison, I&amp;amp;#8217;ve now blagged your code and run it under GNUstep-base (latest from subversion), gnu-gnu-gnu on my Linux laptop.  CPU is a Pentium M running at 800MHz, 2MB cache; box has 512MB RAM.&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Iterations Objs/Iter t/sec&amp;lt;br /&amp;gt;
&lt;br /&gt;1e0 1e6 0.741&amp;lt;br /&amp;gt;
&lt;br /&gt;1e1 1e5 0.603&amp;lt;br /&amp;gt;
&lt;br /&gt;1e2 1e4 0.589&amp;lt;br /&amp;gt;
&lt;br /&gt;1e3 1e3 0.596&amp;lt;br /&amp;gt;
&lt;br /&gt;1e4 1e2 0.604&amp;lt;br /&amp;gt;
&lt;br /&gt;1e5 1e1 0.692&amp;lt;br /&amp;gt;
&lt;br /&gt;1e6 1e0 1.491&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;So, similar results then.  Creating/destroying the ARP every time through the loop &amp;lt;em&amp;gt;hurts&amp;lt;/em&amp;gt;, but when you use less frequent loops the overhead is varying in a non-obvious way, but not by much.  It almost certainly depends on the size of the objects and if they do anything special in -dealloc, too.
&lt;br /&gt;</description><guid isPermaLink="true">3cb7502961c90f37aa088d8ea0879069</guid><pubDate>Thu, 14 Dec 2006 15:47:00 GMT</pubDate></item><item><title>mikeash - 2006-09-13 19:49:00</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>Got it. Yes, that makes sense. Most of the problematic advice stems from attempting to optimize before measuring.
&lt;br /&gt;</description><guid isPermaLink="true">6fbd6e10f663f8d5eca44b8a70794b04</guid><pubDate>Wed, 13 Sep 2006 19:49:00 GMT</pubDate></item><item><title>Kay R&amp;ouml;pke - 2006-09-04 13:08:00</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>Oh, I meant: &amp;amp;#8220;&lt;i&gt;Initially,&lt;/i&gt; dont play tricks to reduce the number of pools created, because creating and destroying a pool is, as the title says, fast.&amp;amp;#8221;&amp;lt;br /&amp;gt;
&lt;br /&gt;That is, unless you know you have a problem, don&amp;amp;#8217;t fiddle with it. Optimize these things later. I wouldn&amp;amp;#8217;t really advise against playing with the number of pools in general, like&amp;lt;br /&amp;gt;
&lt;br /&gt;I wouldn&amp;amp;#8217;t advise against the use of IMP-caching or other optimizations if the code requires it. Sometimes it even makes sense to actually use different zones (just to further deviate from&amp;lt;br /&amp;gt;
&lt;br /&gt;the topic &amp;lt;img src="/blog/pivot/includes/emot/e_121.gif" alt=";)" align="middle" /&amp;gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;Hope that&amp;amp;#8217;s clearer,&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Kay
&lt;br /&gt;</description><guid isPermaLink="true">a852d37d4b534c57db00a0267c4a98d3</guid><pubDate>Mon, 04 Sep 2006 13:08:00 GMT</pubDate></item><item><title>mikeash - 2006-09-03 03:01:00</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>I can&amp;amp;#8217;t figure out where your &amp;amp;#8220;initially&amp;amp;#8221; would go, can you be more specific about what you mean?
&lt;br /&gt;</description><guid isPermaLink="true">1d5ed60c353d9b160c5ac0c9d15952fc</guid><pubDate>Sun, 03 Sep 2006 03:01:00 GMT</pubDate></item><item><title>Kay R&amp;ouml;pke - 2006-09-01 16:16:00</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>&lt;i&gt;Dont play tricks to reduce the number of pools created, because creating and destroying a pool is, as the title says, fast.&lt;/i&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;I&amp;amp;#8217;d add an &lt;i&gt;Initially,&lt;/i&gt; to that sentence, but otherwise, I agree.
&lt;br /&gt;</description><guid isPermaLink="true">509b9fdfe9070e32e0965ec72fecd4ca</guid><pubDate>Fri, 01 Sep 2006 16:16:00 GMT</pubDate></item><item><title>Mike Ash - 2006-06-16 21:31:00</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>The jump from 1 to 10 is very obvious. An NSAutoreleasePool is an object like any other. The work in the loop is allocating a single object. By making an destroying one autorelease pool per loop iteration, you suddenly double the amount of work that&amp;amp;#8217;s being done in the loop. By backing off to doing it only one in ten loops, you&amp;amp;#8217;re only adding 10% to the work that&amp;amp;#8217;s done per iteration. If you take 2.91, divide by two, then add 10%, you get 1.60, which almost perfectly matches the data.&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;I&amp;amp;#8217;m not objecting to rebuilding autorelease pools. Quite the contrary, I&amp;amp;#8217;m advocating creating a new pool every time. Very frequently you will find posts that say you should make an autorelease pool in your loop, but that for efficiency you should only destroy and recreate the pool every N iterations, where N is some number larger than 1, because creating and destroying an autorelease pool is perceived as slow.&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Here&amp;amp;#8217;s a random example pulled off the net (&amp;lt;a href="&lt;a href="http://forums.macrumors.com/showthread.php?t=208029"&gt;http://forums.macrumors.com/showthread.php?t=208029&lt;/a&gt;" rel="nofollow"&amp;gt;&lt;a href="http://forums.macrumors.com/showthread.p..&amp;amp;lt"&gt;http://forums.macrumors.com/showthread.p..&amp;lt;&lt;/a&gt;;/a&amp;gt;):&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&lt;i&gt;It is not necessary to create an autorelease pool at every step. It&amp;amp;#8217;s often only necessary to create one pool per project. The objects you create and detroy will still be cleared out once each pass through the event loop. Bear in mind every time you create and destroy a pool, there is some overhead involved, so you generally only want to create subpools when there is a real need to, such as when lots of memory is being allocated in a loop. Even in that case, you often won&amp;amp;#8217;t want to do a pool for each loop iteration.&lt;/i&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;I see this repeated constantly. But as my data shows, the only time you don&amp;amp;#8217;t want to do a pool for each loop iteration is when your loop&amp;amp;#8217;s work is utterly trivial, and if it&amp;amp;#8217;s so trivial then why are you even doing it, or why do you care if it&amp;amp;#8217;s fast?&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;I&amp;amp;#8217;m advocating that if you have a long-running loop that autoreleases objects and you need to make a pool, just make one pool per iteration. Don&amp;amp;#8217;t play tricks to reduce the number of pools created, because creating and destroying a pool is, as the title says, fast.
&lt;br /&gt;</description><guid isPermaLink="true">e84eefdbeaf28b368a1959bbabba2964</guid><pubDate>Fri, 16 Jun 2006 21:31:00 GMT</pubDate></item><item><title>Robert 'Groby' Blum - 2006-06-16 16:55:00</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>Hm. That&amp;amp;#8217;s not enough data to convince me either way. There&amp;amp;#8217;s a couple of things that I&amp;amp;#8217;d like to see. One is finding oy &amp;lt;strong&amp;gt;why&amp;lt;/strong&amp;gt; the jump from 1 to 10 autorelease pools occurs &amp;amp;#8211; that 50% speedup is just plain mysterious. And, BTW, is an excellent justification for re-creating autorelease pools every time. If &amp;amp;#8211; and that&amp;amp;#8217;s the second thing &amp;amp;#8211; this advantage actually occurs for any number of objects. I&amp;amp;#8217;ve got no idea if we&amp;amp;#8217;ll see the same drastic speedup if we only have 10, 100, or 1000 objects.&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;As a final note, from the data so far it seems like rebuilding AR pools &amp;lt;strong&amp;gt;does&amp;lt;/strong&amp;gt; speed you up significantly. If it does it consistently, it&amp;amp;#8217;s not a premature optimization &amp;amp;#8211; it&amp;amp;#8217;s a best practice. After all, it&amp;amp;#8217;s not like it adds hideous code bloat &amp;amp;#8211; it&amp;amp;#8217;s a couple of &amp;amp;#8220;by-rote&amp;amp;#8221; lines.
&lt;br /&gt;</description><guid isPermaLink="true">57204143496a951fa1d4ceaef441e55b</guid><pubDate>Fri, 16 Jun 2006 16:55:00 GMT</pubDate></item><item><title>Felix - 2006-06-08 19:51:00</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>Hi. &amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;The formula was just a wild guess which I then parametrized to fit the given numbers. The &amp;amp;#8220;roundness&amp;amp;#8221; of the factors is pure coincidence and I was quite astonished myself. Unfortunately I found out why this formula would have to be verified with different data to have any value: If you compute the part 1.5e-10*S^2 alone, you will see get the results&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;150.000&amp;lt;br /&amp;gt;
&lt;br /&gt;1.500&amp;lt;br /&amp;gt;
&lt;br /&gt;0.015&amp;lt;br /&amp;gt;
&lt;br /&gt;0.000&amp;lt;br /&amp;gt;
&lt;br /&gt;0.000&amp;lt;br /&amp;gt;
&lt;br /&gt;0.000&amp;lt;br /&amp;gt;
&lt;br /&gt;0.000&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;This shows that effectively only the first realization changes anything at all in the result and that the linear part 1.5e-3*N takes over for all the other results. While this does not yet mean that the relationship is completely wrong (it sort of proves the constant time per object allocation) it strongly suggests that further investigation is necessary for further application. I fear that memory management has a lot more complex time / size curves (see &amp;lt;a href="&lt;a href="http://ridiculousfish.com/blog/archives/2006/05/16/36/"&gt;http://ridiculousfish.com/blog/archives/2006/05/16/36/&lt;/a&gt;" rel="nofollow"&amp;gt;&lt;a href="http://ridiculousfish.com/blog/archives/..&amp;amp;lt"&gt;http://ridiculousfish.com/blog/archives/..&amp;lt;&lt;/a&gt;;/a&amp;gt; for example). &amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Hmm. I was amazed though when I first saw the result.&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Cheers,&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Felix
&lt;br /&gt;</description><guid isPermaLink="true">992856904086b2b6e5244b931617f93a</guid><pubDate>Thu, 08 Jun 2006 19:51:00 GMT</pubDate></item><item><title>mikeash - 2006-06-08 04:04:00</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>Felix, your numbers are very interesting. The 1.5s in your formula seem like very round numbers, considering how close a fit they give. Where did that formula come from, is it just a straight curve fit that happens to give exactly 1.5, or is there some theoretical basis to it?
&lt;br /&gt;</description><guid isPermaLink="true">e12a0b29bde0dd7a68d52c7c767145b3</guid><pubDate>Thu, 08 Jun 2006 04:04:00 GMT</pubDate></item><item><title>foobaz - 2006-06-07 23:16:00</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>Thanks for the excellent research.
&lt;br /&gt;</description><guid isPermaLink="true">292612b361a23110e4b732aa501358bd</guid><pubDate>Wed, 07 Jun 2006 23:16:00 GMT</pubDate></item><item><title>Felix - 2006-06-07 19:59:00</title><link>http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html#comments</link><description>Interesting numbers!&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If you take the number of simultaneous objects S and the number of allocations N you can reproduce the measured time t spent on allocation and memory management with the formula T=1.5e-10*S^2+1.5e-3*N:&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Objects_ O/Pool___ t(ms) S&amp;amp;#8212;&amp;amp;#8212;&amp;amp;#8212;&amp;amp;#8212;N&amp;amp;#8212;&amp;amp;#8212;&amp;amp;#8212;&amp;amp;#8212;T(ms) T/t&amp;lt;br /&amp;gt;
&lt;br /&gt;1000000 1000000 1650 1000001 1000001 1650 100.00%&amp;lt;br /&amp;gt;
&lt;br /&gt;1000000 0100000 1590 0100001 1000010 1502 094.43%&amp;lt;br /&amp;gt;
&lt;br /&gt;1000000 0010000 1480 0010001 1000100 1500 101.36%&amp;lt;br /&amp;gt;
&lt;br /&gt;1000000 0001000 1460 0001001 1001000 1501 102.84%&amp;lt;br /&amp;gt;
&lt;br /&gt;1000000 0000100 1430 0000101 1010000 1515 105.94%&amp;lt;br /&amp;gt;
&lt;br /&gt;1000000 0000010 1640 0000011 1100000 1650 100.61%&amp;lt;br /&amp;gt;
&lt;br /&gt;1000000 0000001 2910 0000002 2000000 3000 103.09%&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;The constant factors 1.5e-10 and 1.5e-3 might be irrelevant for other cases than this, but the following result seems valid:&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Total allocation time is directly proportional to N. Memory management time is proportional to S^2.&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;lt;br /&amp;gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Felix
&lt;br /&gt;</description><guid isPermaLink="true">e227208f4689de83909b625d680fc438</guid><pubDate>Wed, 07 Jun 2006 19:59:00 GMT</pubDate></item></channel></rss>
