title: Do loops and convenience methods cause memory peaks with ARC?
body: <p>I'm working with ARC and seeing some strange behavior when modifying strings in a loop. </p>
  
  <p>In my situation, I'm looping using NSXMLParser delegate callbacks, but I see the same exact behavior and symptoms using a demo project and sample code which simply modifies some <code>NSString</code> objects.</p>
  
  <p>You can <a href="https://github.com/MosheBerman/loopy-leaky-peaky-loops" rel="noreferrer">download the demo project from GitHub</a>, just uncomment one of the four method calls in the main view controller's <code>viewDidLoad</code> method to test the different behaviors.</p>
  
  <p>For simplicity's sake, here's a simple loop which I've stuck into an empty single-view application. I pasted this code directly into the <code>viewDidLoad</code> method. It runs before the view appears, so the screen is black until the loop finishes. </p>
  
  <pre><code>NSString *text;
  
  for (NSInteger i = 0; i &lt; 600000000; i++) {
  
      NSString *newText = [text stringByAppendingString:@" Hello"];
  
      if (text) {
          text = newText;
      }else{
          text = @"";
      }
  }
  </code></pre>
  
  <p>The following code also keeps eating memory until the loop completes: </p>
  
  <pre><code>NSString *text;
  
  for (NSInteger i = 0; i &lt; 600000000; i++) {
  
      if (text) {
          text = [text stringByAppendingString:@" Hello"];
      }else{
          text = @"";
      }
  }
  </code></pre>
  
  <p>Here's what these two loops loop like in Instruments, with the Allocations tool running:</p>
  
  <p><img src="https://i.stack.imgur.com/8qtlc.jpg" alt="Instruments profiling repeating string manipulation"></p>
  
  <p>See? Gradual and steady memory usage, until a whole bunch of memory warnings and then the app dies, naturally.</p>
  
  <p>Next, I've tried something a little different. I used an instance of <code>NSMutableString</code>, like so:</p>
  
  <pre><code>NSMutableString *text;
  
  for (NSInteger i = 0; i &lt; 600000000; i++) {
  
      if (text) {
          [text appendString:@" Hello"];
      }else{
          text = [@"" mutableCopy];
      }
  }
  </code></pre>
  
  <p>This code seems to perform a lot better, but still crashes. Here's what that looks like:</p>
  
  <p><img src="https://i.stack.imgur.com/XUYQY.jpg" alt="NSMutableStrings being profiles instead"></p>
  
  <p>Next, I tried this on a smaller dataset, to see if either loop can survive the build up long enough to finish. Here's the <code>NSString</code> version:</p>
  
  <pre><code>NSString *text;
  
  for (NSInteger i = 0; i &lt; 1000000; i++) {
  
      if (text) {
          text = [text stringByAppendingString:@" Hello"];
      }else{
          text = @"";
      }
  }
  </code></pre>
  
  <p>It crashes as well, and the resultant memory graph looks similar to the first one generated using this code:</p>
  
  <p><img src="https://i.stack.imgur.com/1C1oi.jpg" alt="NSString crashes again"></p>
  
  <p>Using <code>NSMutableString</code>, the same million-iteration loop not only succeeds, but it does in a lot less time. Here's the code:</p>
  
  <pre><code>NSMutableString *text;
  
  for (NSInteger i = 0; i &lt; 1000000; i++) {
  
      if (text) {
          [text appendString:@" Hello"];
      }else{
          text = [@"" mutableCopy];
      }
  }
  </code></pre>
  
  <p>And have a look at the memory usage graph:</p>
  
  <p><img src="https://i.stack.imgur.com/qZmdH.jpg" alt="NSMutableStrings seem to work with smaller datasets"></p>
  
  <p>The short spike in the beginning is the memory usage incurred by the loop. Remember when I noted that seemingly irrelevant fact that the screen is black during the processing of the loop, because I run it in viewDidLoad? Immediately after that spike, the view appears. So it appears that not only do NSMutableStrings handle memory more efficiently in this scenario, but they're also much faster. Fascinating. </p>
  
  <p>Now, back to my actual scenario... I'm using <code>NSXMLParser</code> to parse out the results of an API call. I've created Objective-C objects to match my XML response structure. So, consider for example, an XML response looking something like this:</p>
  
  <pre><code>&lt;person&gt;
  &lt;firstname&gt;John&lt;/firstname&gt;
  &lt;lastname&gt;Doe&lt;/lastname&gt;
  &lt;/person&gt;
  </code></pre>
  
  <p>My object would look like this:</p>
  
  <pre><code>@interface Person : NSObject
  
  @property (nonatomic, strong) NSString *firstName;
  @property (nonatomic, strong) NSString *lastName;
  
  @end
  </code></pre>
  
  <p>Now, in my NSXMLParser delegate, I'd go ahead and loop through my XML, and I'd keep track of the current element (I don't need a full hierarchy representation since my data is rather flat, it's a dump of a MSSQL database as XML) and then in the <code>foundCharacters</code> method, I'd run something like this:</p>
  
  <pre><code>- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
    if((currentProperty is EqualToString:@"firstname"]){
      self.workingPerson.firstname = [self.workingPerson.firstname stringByAppendingString:string]; 
    }
  }
  </code></pre>
  
  <p>This code is much like the first code. I'm effectively looping through the XML using <code>NSXMLParser</code>, so if I were to log all of my method calls, I'd see something like this:</p>
  
  <blockquote>
    <p>parserDidStartDocument:
    parser:didStartElement:namespaceURI:qualifiedName:attributes:
    parser:foundCharacters:
    parser:didStartElement:namespaceURI:qualifiedName:
    parser:didStartElement:namespaceURI:qualifiedName:attributes:
    parser:foundCharacters:
    parser:didStartElement:namespaceURI:qualifiedName:
    parser:didStartElement:namespaceURI:qualifiedName:attributes:
    parser:foundCharacters:
    parser:didStartElement:namespaceURI:qualifiedName:
    parserDidEndDocument:</p>
  </blockquote>
  
  <p>See the pattern? It's a loop. Note that it's possible to have multiple consecutive calls to <code>parser:foundCharacters:</code> as well, which is why we append the property to previous values. </p>
  
  <p>To wrap it up, there are two problems here. First of all, memory build up in any sort of loop seems to crash the app. Second, using <code>NSMutableString</code> with properties is not so elegant, and I'm not even sure that it's working as intended.</p>
  
  <p>In general, is there a way to overcome this memory buildup while looping through strings using ARC? Is there something specific to NSXMLParser that I can do?</p>
  
  <p><strong>Edit:</strong></p>
  
  <p>Initial tests indicate that even using a second <code>@autoreleasepool{...}</code> doesn't seem to fix the issue.</p>
  
  <p>The objects have to go <em>somewhere</em> in memory while thwy exist, and they're still there until the end of the runloop, when the autorelease pools can drain. </p>
  
  <p>This doesn't fix anything in the strings situation as far as NSXMLParser goes, it might, because the loop is spread across method calls - need to test further.</p>
  
  <p>(Note that I call this a memory peak, because in theory, ARC will clean up memory at some point, just not until after it peaks out. Nothing is actually leaking, but it's having the same effect.)  </p>
  
  <p><strong>Edit 2:</strong></p>
  
  <p>Sticking the autorelease pool inside of the loop has some interesting effects. It seems to almost mitigate the buildup when appending to an <code>NSString</code> object:</p>
  
  <pre><code>NSString *text;
  
  for (NSInteger i = 0; i &lt; 600000000; i++) {
  
          @autoreleasepool {
              if (text) {
                  text = [text stringByAppendingString:@" Hello"];
              }else{
                  text = [@"" mutableCopy];
              }
          }
      }
  </code></pre>
  
  <p>The Allocations trace looks like so:</p>
  
  <p><img src="https://i.stack.imgur.com/xIno9.jpg" alt="enter image description here"></p>
  
  <p>I do notice a gradual buildup of memory over time, but it's to the tune of about a 150 kilobytes, not the 350 megabytes seen earlier. However, this code, using <code>NSMutableString</code> behaves the same as it did without the autorelease pool:</p>
  
  <pre><code>NSMutableString *text;
  
  for (NSInteger i = 0; i &lt; 600000000; i++) {
  
          @autoreleasepool {
              if (text) {
                  [text appendString:@" Hello"];
              }else{
                  text = [@"" mutableCopy];
              }
          }
      }
  </code></pre>
  
  <p>And the Allocations trace:</p>
  
  <p><img src="https://i.stack.imgur.com/CAOvT.jpg" alt="NSMutableString is apparently immune to the autorelease pool"></p>
  
  <p>It would appear that NSMutableString is apparently immune to the autorelease pool. I'm not sure why, but at first guess, I'd tie this in with what we saw earlier, that <code>NSMutableString</code> can handle about a million iterations on its own, whereas <code>NSString</code> cannot.</p>
  
  <p>So, what's the correct way of resolving this? </p>